arpakitlib 1.8.19__py3-none-any.whl → 1.8.20__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 (28) hide show
  1. arpakitlib/_arpakit_project_template_v_5/project/api/auth.py +136 -211
  2. arpakitlib/_arpakit_project_template_v_5/project/api/exception_handler.py +1 -2
  3. arpakitlib/_arpakit_project_template_v_5/project/api/router/admin/get_arpakitlib_project_template_info.py +7 -1
  4. arpakitlib/_arpakit_project_template_v_5/project/api/router/admin/get_auth_data.py +6 -8
  5. arpakitlib/_arpakit_project_template_v_5/project/api/router/admin/main_router.py +17 -0
  6. arpakitlib/_arpakit_project_template_v_5/project/api/router/admin/raise_fake_error.py +27 -0
  7. arpakitlib/_arpakit_project_template_v_5/project/api/router/client/get_errors_info.py +4 -8
  8. arpakitlib/_arpakit_project_template_v_5/project/api/router/client/main_router.py +7 -0
  9. arpakitlib/_arpakit_project_template_v_5/project/api/router/general/main_router.py +5 -1
  10. arpakitlib/_arpakit_project_template_v_5/project/api/router/{client → general}/now_utc_datetime.py +1 -1
  11. arpakitlib/_arpakit_project_template_v_5/project/api/schema/out/admin/user.py +1 -1
  12. arpakitlib/_arpakit_project_template_v_5/project/api/schema/out/admin/user_token.py +1 -1
  13. arpakitlib/_arpakit_project_template_v_5/project/core/settings.py +3 -17
  14. arpakitlib/_arpakit_project_template_v_5/project/sqlalchemy_db_/sqlalchemy_model/api_key.py +1 -1
  15. arpakitlib/_arpakit_project_template_v_5/project/sqlalchemy_db_/sqlalchemy_model/user.py +1 -1
  16. arpakitlib/_arpakit_project_template_v_5/project/sqlalchemy_db_/sqlalchemy_model/user_token.py +1 -1
  17. arpakitlib/_arpakit_project_template_v_5/project/test_data/make_test_api_keys.py +35 -0
  18. arpakitlib/_arpakit_project_template_v_5/project/test_data/make_test_data_1.py +4 -2
  19. arpakitlib/_arpakit_project_template_v_5/project/test_data/make_test_data_2.py +4 -2
  20. arpakitlib/_arpakit_project_template_v_5/project/test_data/make_test_data_3.py +4 -2
  21. arpakitlib/_arpakit_project_template_v_5/project/test_data/make_test_data_4.py +4 -2
  22. arpakitlib/_arpakit_project_template_v_5/project/test_data/make_test_data_5.py +4 -2
  23. {arpakitlib-1.8.19.dist-info → arpakitlib-1.8.20.dist-info}/METADATA +1 -1
  24. {arpakitlib-1.8.19.dist-info → arpakitlib-1.8.20.dist-info}/RECORD +27 -26
  25. arpakitlib/_arpakit_project_template_v_5/project/api/auth2.py +0 -218
  26. {arpakitlib-1.8.19.dist-info → arpakitlib-1.8.20.dist-info}/LICENSE +0 -0
  27. {arpakitlib-1.8.19.dist-info → arpakitlib-1.8.20.dist-info}/WHEEL +0 -0
  28. {arpakitlib-1.8.19.dist-info → arpakitlib-1.8.20.dist-info}/entry_points.txt +0 -0
@@ -1,4 +1,5 @@
1
- from typing import Callable
1
+ import functools
2
+ from typing import Callable, Any
2
3
 
3
4
  import fastapi
4
5
  import fastapi.exceptions
@@ -8,10 +9,10 @@ import sqlalchemy
8
9
  from fastapi import Security
9
10
  from fastapi.security import APIKeyHeader
10
11
  from pydantic import BaseModel, ConfigDict
12
+ from sqlalchemy.orm import joinedload
11
13
 
12
14
  from arpakitlib.ar_func_util import is_async_func, is_sync_func
13
15
  from arpakitlib.ar_json_util import transfer_data_to_json_str_to_data
14
- from arpakitlib.ar_type_util import raise_for_type
15
16
  from project.api.const import APIErrorCodes
16
17
  from project.api.exception import APIException
17
18
  from project.core.settings import get_cached_settings
@@ -22,70 +23,27 @@ from project.sqlalchemy_db_.sqlalchemy_model import ApiKeyDBM, UserTokenDBM
22
23
  class APIAuthData(BaseModel):
23
24
  model_config = ConfigDict(extra="forbid", arbitrary_types_allowed=True, from_attributes=True)
24
25
 
25
- require_api_key_string: bool = False
26
- require_user_token_string: bool = False
27
-
28
- require_correct_api_key: bool = False
29
- require_correct_user_token: bool = False
30
-
31
- require_mode_type: str | None = None
32
- require_not_mode_type: str | None = None
33
-
34
- current_mode_type: str | None = None
35
-
36
26
  api_key_string: str | None = None
37
27
  user_token_string: str | None = None
38
28
 
39
29
  is_api_key_correct: bool | None = None
40
- is_user_token_correct: bool | None = None
41
30
 
42
31
  api_key_dbm: ApiKeyDBM | None = None
43
32
  user_token_dbm: UserTokenDBM | None = None
44
33
 
34
+ prod_mode: bool = False
45
35
 
46
- def api_auth(
47
- *,
48
- require_api_key_string: bool = False,
49
- require_user_token_string: bool = False,
50
-
51
- require_correct_api_key: bool = False,
52
- require_correct_user_token: bool = False,
36
+ extra_data: dict[str, Any] = {}
53
37
 
54
- require_mode_type: str | None = None,
55
- require_not_mode_type: str | None = None,
56
38
 
57
- is_api_key_correct_func: Callable | None = None,
58
- is_user_token_correct_func: Callable | None = None,
59
- correct_api_keys: str | list[str] | None = None,
60
- correct_user_tokens: str | list[str] | None = None,
39
+ def api_auth(
40
+ *,
41
+ middlewares: list[Callable] | None = None
61
42
  ) -> Callable:
62
- if isinstance(correct_api_keys, str):
63
- correct_api_keys = [correct_api_keys]
64
- if correct_api_keys is not None:
65
- raise_for_type(correct_api_keys, list)
66
-
67
- if is_api_key_correct_func is None and correct_api_keys is not None:
68
- is_api_key_correct_func = (
69
- lambda *args, **kwargs_: kwargs_["api_auth_data"].api_key_string in correct_api_keys
70
- )
71
-
72
- if isinstance(correct_user_tokens, str):
73
- correct_user_tokens = [correct_user_tokens]
74
- if correct_user_tokens is not None:
75
- raise_for_type(correct_user_tokens, list)
76
-
77
- if is_user_token_correct_func is None and correct_user_tokens is not None:
78
- is_user_token_correct_func = (
79
- lambda *args, **kwargs_: kwargs_["api_auth_data"].user_token_string in correct_user_tokens
80
- )
81
-
82
- if require_correct_api_key is True:
83
- require_api_key_string = True
43
+ if middlewares is None:
44
+ middlewares = []
84
45
 
85
- if require_correct_user_token is True:
86
- require_user_token_string = True
87
-
88
- async def func(
46
+ async def async_func(
89
47
  *,
90
48
  ac: fastapi.security.HTTPAuthorizationCredentials | None = fastapi.Security(
91
49
  fastapi.security.HTTPBearer(auto_error=False)
@@ -97,16 +55,10 @@ def api_auth(
97
55
  ) -> APIAuthData:
98
56
 
99
57
  api_auth_data = APIAuthData(
100
- require_api_key_string=require_api_key_string,
101
- require_user_token_string=require_user_token_string,
102
- require_correct_api_key=require_correct_api_key,
103
- require_correct_user_token=require_correct_user_token,
104
- require_mode_type=require_mode_type,
105
- require_not_mode_type=require_not_mode_type,
106
- current_mode_type=get_cached_settings().mode_type
58
+ prod_mode=get_cached_settings().prod_mode
107
59
  )
108
60
 
109
- # parse api_key
61
+ # parse api_key_string
110
62
 
111
63
  api_auth_data.api_key_string = api_key_string
112
64
 
@@ -116,6 +68,8 @@ def api_auth(
116
68
  api_auth_data.api_key_string = request.headers["api-key"]
117
69
  if not api_auth_data.api_key_string and "apikey" in request.headers.keys():
118
70
  api_auth_data.api_key_string = request.headers["apikey"]
71
+ if not api_auth_data.api_key_string and "api_key_string" in request.headers.keys():
72
+ api_auth_data.api_key_string = request.headers["api_key_string"]
119
73
 
120
74
  if not api_auth_data.api_key_string and "api_key" in request.query_params.keys():
121
75
  api_auth_data.api_key_string = request.query_params["api_key"]
@@ -123,13 +77,15 @@ def api_auth(
123
77
  api_auth_data.api_key_string = request.query_params["api-key"]
124
78
  if not api_auth_data.api_key_string and "apikey" in request.query_params.keys():
125
79
  api_auth_data.api_key_string = request.query_params["apikey"]
80
+ if not api_auth_data.api_key_string and "api_key_string" in request.query_params.keys():
81
+ api_auth_data.api_key_string = request.query_params["api_key_string"]
126
82
 
127
83
  if api_auth_data.api_key_string:
128
84
  api_auth_data.api_key_string = api_auth_data.api_key_string.strip()
129
85
  if not api_auth_data.api_key_string:
130
86
  api_auth_data.api_key_string = None
131
87
 
132
- # parse user token
88
+ # parse user_token_string
133
89
 
134
90
  api_auth_data.user_token_string = ac.credentials if ac and ac.credentials and ac.credentials.strip() else None
135
91
 
@@ -158,196 +114,165 @@ def api_auth(
158
114
  if not api_auth_data.user_token_string:
159
115
  api_auth_data.user_token_string = None
160
116
 
161
- # require_mode_type
117
+ # is_api_key_correct
162
118
 
163
- if require_mode_type is not None:
164
- if get_cached_settings().mode_type != require_mode_type:
165
- raise APIException(
166
- status_code=fastapi.status.HTTP_401_UNAUTHORIZED,
167
- error_code=APIErrorCodes.cannot_authorize,
168
- error_data=transfer_data_to_json_str_to_data(api_auth_data.model_dump())
169
- )
119
+ if api_auth_data.api_key_string is not None:
120
+ if get_cached_settings().api_correct_api_keys is None:
121
+ api_auth_data.is_api_key_correct = None
122
+ else:
123
+ api_auth_data.is_api_key_correct = api_auth_data.api_key_string in get_cached_settings().api_correct_api_keys
170
124
 
171
- # require_not_mode_type
125
+ # api_key_dbm
172
126
 
173
- if require_not_mode_type is not None:
174
- if get_cached_settings().mode_type == require_not_mode_type:
175
- raise APIException(
176
- status_code=fastapi.status.HTTP_401_UNAUTHORIZED,
177
- error_code=APIErrorCodes.cannot_authorize,
178
- error_data=transfer_data_to_json_str_to_data(api_auth_data.model_dump())
179
- )
127
+ if api_auth_data.api_key_string is not None:
128
+ if get_cached_sqlalchemy_db() is not None:
129
+ async with get_cached_sqlalchemy_db().new_async_session() as async_session:
130
+ api_auth_data.api_key_dbm = await async_session.scalar(
131
+ sqlalchemy.select(ApiKeyDBM).where(ApiKeyDBM.value == api_auth_data.api_key_string)
132
+ )
180
133
 
181
- # require_api_key_string
134
+ # user_token_dbm
182
135
 
183
- if require_api_key_string and not api_auth_data.api_key_string:
184
- raise APIException(
185
- status_code=fastapi.status.HTTP_401_UNAUTHORIZED,
186
- error_code=APIErrorCodes.cannot_authorize,
187
- error_data=transfer_data_to_json_str_to_data(api_auth_data.model_dump())
188
- )
136
+ if api_auth_data.api_key_string is not None:
137
+ if get_cached_sqlalchemy_db() is not None:
138
+ async with get_cached_sqlalchemy_db().new_async_session() as async_session:
139
+ api_auth_data.user_token_dbm = await async_session.scalar(
140
+ sqlalchemy.select(UserTokenDBM)
141
+ .options(joinedload(UserTokenDBM.user))
142
+ .where(UserTokenDBM.value == api_auth_data.user_token_string)
143
+ )
189
144
 
190
- # require_token_string
191
-
192
- if require_user_token_string and not api_auth_data.user_token_string:
193
- raise APIException(
194
- status_code=fastapi.status.HTTP_401_UNAUTHORIZED,
195
- error_code=APIErrorCodes.cannot_authorize,
196
- error_data=transfer_data_to_json_str_to_data(api_auth_data.model_dump())
197
- )
145
+ # middlewares
198
146
 
199
- # is_api_key_correct_func
147
+ for middleware in middlewares:
148
+ api_auth_data.extra_data[middleware.__name__] = True
200
149
 
201
- if is_api_key_correct_func is not None:
202
- if is_async_func(is_api_key_correct_func):
203
- await is_api_key_correct_func(
150
+ for middleware in middlewares:
151
+ if is_async_func(middleware):
152
+ await middleware(
204
153
  api_auth_data=api_auth_data,
205
154
  request=request
206
155
  )
207
- elif is_sync_func(is_api_key_correct_func):
208
- is_api_key_correct_func(
156
+ elif is_sync_func(middleware):
157
+ middleware(
209
158
  api_auth_data=api_auth_data,
210
159
  request=request
211
160
  )
212
161
  else:
213
- raise TypeError("unknown validate_api_key_func type")
162
+ raise TypeError(f"unknown middleware type, {middleware.__name__}")
214
163
 
215
- # is_user_token_correct_func
164
+ return api_auth_data
216
165
 
217
- if is_user_token_correct_func is not None:
218
- if is_async_func(is_user_token_correct_func):
219
- await is_user_token_correct_func(
220
- api_auth_data=api_auth_data,
221
- request=request
222
- )
223
- elif is_sync_func(is_user_token_correct_func):
224
- is_user_token_correct_func(
225
- api_auth_data=api_auth_data,
226
- request=request
227
- )
228
- else:
229
- raise TypeError("unknown validate_token_func type")
166
+ return async_func
230
167
 
231
- # require_correct_api_key
232
168
 
233
- if require_correct_api_key:
234
- if not api_auth_data.is_api_key_correct:
235
- raise APIException(
236
- status_code=fastapi.status.HTTP_401_UNAUTHORIZED,
237
- error_code=APIErrorCodes.cannot_authorize,
238
- error_description="not api_auth_data.is_api_key_correct",
239
- error_data=transfer_data_to_json_str_to_data(api_auth_data.model_dump()),
240
- )
169
+ def require_prod_mode_api_middleware():
170
+ @functools.wraps(require_prod_mode_api_middleware)
171
+ def func(*, api_auth_data: APIAuthData, request: fastapi.requests.Request):
172
+ if not get_cached_settings().prod_mode:
173
+ raise APIException(
174
+ status_code=fastapi.status.HTTP_401_UNAUTHORIZED,
175
+ error_code=APIErrorCodes.cannot_authorize,
176
+ error_description=f"prod_mode={get_cached_settings().prod_mode}",
177
+ error_data=transfer_data_to_json_str_to_data(api_auth_data.model_dump())
178
+ )
241
179
 
242
- # require_correct_token
180
+ return func
243
181
 
244
- if require_correct_user_token:
245
- if not api_auth_data.is_user_token_correct:
246
- raise APIException(
247
- status_code=fastapi.status.HTTP_401_UNAUTHORIZED,
248
- error_code=APIErrorCodes.cannot_authorize,
249
- error_description="not api_auth_data.is_user_token_correct",
250
- error_data=transfer_data_to_json_str_to_data(api_auth_data.model_dump())
251
- )
252
182
 
253
- return api_auth_data
183
+ def require_not_prod_mode_api_middleware():
184
+ @functools.wraps(require_not_prod_mode_api_middleware)
185
+ def func(*, api_auth_data: APIAuthData, request: fastapi.requests.Request):
186
+ if get_cached_settings().prod_mode:
187
+ raise APIException(
188
+ status_code=fastapi.status.HTTP_401_UNAUTHORIZED,
189
+ error_code=APIErrorCodes.cannot_authorize,
190
+ error_description=f"prod_mode={get_cached_settings().prod_mode}",
191
+ error_data=transfer_data_to_json_str_to_data(api_auth_data.model_dump())
192
+ )
254
193
 
255
194
  return func
256
195
 
257
196
 
258
- def correct_api_keys_from_settings__is_api_key_correct_func() -> Callable:
259
- async def async_func(
260
- *,
261
- api_auth_data: APIAuthData,
262
- request: fastapi.requests.Request,
263
- ):
264
- if get_cached_settings().api_correct_api_keys is None:
265
- api_auth_data.is_api_key_correct = False
266
- return
197
+ def require_api_key_string_api_middleware():
198
+ @functools.wraps(require_api_key_string_api_middleware)
199
+ def func(*, api_auth_data: APIAuthData, request: fastapi.requests.Request):
267
200
  if api_auth_data.api_key_string is None:
268
- api_auth_data.is_api_key_correct = False
269
- return
270
- if api_auth_data.api_key_string.strip() not in get_cached_settings().api_correct_api_keys:
271
- api_auth_data.is_api_key_correct = False
272
- return
273
- api_auth_data.is_api_key_correct = True
274
- return
201
+ raise APIException(
202
+ status_code=fastapi.status.HTTP_401_UNAUTHORIZED,
203
+ error_code=APIErrorCodes.cannot_authorize,
204
+ error_description="api_key_string is required",
205
+ error_data=transfer_data_to_json_str_to_data(api_auth_data.model_dump())
206
+ )
275
207
 
276
- return async_func
208
+ return func
277
209
 
278
210
 
279
- def correct_tokens_from_settings__is_user_token_correct_func() -> Callable:
280
- async def async_func(
281
- *,
282
- api_auth_data: APIAuthData,
283
- request: fastapi.requests.Request,
284
- ):
285
- if get_cached_settings().api_correct_tokens is None:
286
- api_auth_data.is_api_key_correct = False
287
- return
211
+ def require_user_token_string_api_middleware():
212
+ @functools.wraps(require_user_token_string_api_middleware)
213
+ def func(*, api_auth_data: APIAuthData, request: fastapi.requests.Request):
288
214
  if api_auth_data.user_token_string is None:
289
- api_auth_data.is_api_key_correct = False
290
- return
291
- if api_auth_data.user_token_string.strip() not in get_cached_settings().api_correct_tokens:
292
- api_auth_data.is_api_key_correct = False
293
- return
294
- api_auth_data.is_api_key_correct = True
295
- return
296
-
297
- return async_func
215
+ raise APIException(
216
+ status_code=fastapi.status.HTTP_401_UNAUTHORIZED,
217
+ error_code=APIErrorCodes.cannot_authorize,
218
+ error_description="user_token_string is required",
219
+ error_data=transfer_data_to_json_str_to_data(api_auth_data.model_dump())
220
+ )
298
221
 
222
+ return func
299
223
 
300
- def correct_api_key_from_sqlalchemy_db__is_api_key_correct_func() -> Callable:
301
- async def async_func(
302
- *,
303
- api_auth_data: APIAuthData,
304
- request: fastapi.requests.Request,
305
- ):
306
- if api_auth_data.api_key_string is None:
307
- api_auth_data.is_api_key_correct = False
308
- return
309
224
 
310
- async with get_cached_sqlalchemy_db().new_async_session() as session:
311
- api_auth_data.api_key_dbm = await session.scalar(
312
- sqlalchemy.select(ApiKeyDBM).where(ApiKeyDBM.value == api_auth_data.api_key_string)
225
+ def require_correct_api_key_dbm_api_middleware():
226
+ @functools.wraps(require_correct_api_key_dbm_api_middleware)
227
+ def func(*, api_auth_data: APIAuthData, request: fastapi.requests.Request):
228
+ if not api_auth_data.is_api_key_correct:
229
+ raise APIException(
230
+ status_code=fastapi.status.HTTP_401_UNAUTHORIZED,
231
+ error_code=APIErrorCodes.cannot_authorize,
232
+ error_description="api_key_string is not correct",
233
+ error_data=transfer_data_to_json_str_to_data(api_auth_data.model_dump())
313
234
  )
314
235
 
315
- if api_auth_data.api_key_dbm is None or not api_auth_data.api_key_dbm.is_enabled:
316
- api_auth_data.is_api_key_correct = False
317
- return
318
-
319
- api_auth_data.is_api_key_correct = True
320
- return True
236
+ return func
321
237
 
322
- return async_func
323
238
 
239
+ def require_api_key_dbm_api_middleware(*, require_active: bool = True):
240
+ @functools.wraps(require_api_key_dbm_api_middleware)
241
+ async def async_func(*, api_auth_data: APIAuthData, request: fastapi.requests.Request):
242
+ if api_auth_data.api_key_dbm is None:
243
+ raise APIException(
244
+ status_code=fastapi.status.HTTP_401_UNAUTHORIZED,
245
+ error_code=APIErrorCodes.cannot_authorize,
246
+ error_description="api_key_dbm is required",
247
+ error_data=transfer_data_to_json_str_to_data(api_auth_data.model_dump())
248
+ )
249
+ if require_active and not api_auth_data.api_key_dbm.is_active:
250
+ raise APIException(
251
+ status_code=fastapi.status.HTTP_401_UNAUTHORIZED,
252
+ error_code=APIErrorCodes.cannot_authorize,
253
+ error_description="api_key_dbm is not active",
254
+ error_data=transfer_data_to_json_str_to_data(api_auth_data.model_dump())
255
+ )
324
256
 
325
- def correct_user_token_from_sqlalchemy_db__is_user_token_correct_func(
326
- *, require_user_roles: list[str] | None = None
327
- ) -> Callable:
328
- async def async_func(
329
- *,
330
- api_auth_data: APIAuthData,
331
- request: fastapi.requests.Request,
332
- ):
333
- if api_auth_data.user_token_string is None:
334
- api_auth_data.is_user_token_correct = False
335
- return
257
+ return async_func
336
258
 
337
- with get_cached_sqlalchemy_db().new_session() as session:
338
- api_auth_data.user_token_dbm = session.query(
339
- UserTokenDBM
340
- ).filter(
341
- UserTokenDBM.value == api_auth_data.user_token_string
342
- ).one_or_none()
343
259
 
260
+ def require_user_token_dbm_api_middleware(*, require_active: bool = True):
261
+ @functools.wraps(require_user_token_dbm_api_middleware)
262
+ async def async_func(*, api_auth_data: APIAuthData, request: fastapi.requests.Request):
344
263
  if api_auth_data.user_token_dbm is None:
345
- api_auth_data.is_user_token_correct = False
346
- return
347
- if not api_auth_data.user_token_dbm.is_enabled:
348
- pass
349
-
350
- api_auth_data.is_user_token_correct = True
351
- return
264
+ raise APIException(
265
+ status_code=fastapi.status.HTTP_401_UNAUTHORIZED,
266
+ error_code=APIErrorCodes.cannot_authorize,
267
+ error_description="user_key_dbm is required",
268
+ error_data=transfer_data_to_json_str_to_data(api_auth_data.model_dump())
269
+ )
270
+ if require_active and not api_auth_data.user_token_dbm.is_active:
271
+ raise APIException(
272
+ status_code=fastapi.status.HTTP_401_UNAUTHORIZED,
273
+ error_code=APIErrorCodes.cannot_authorize,
274
+ error_description="user_key_dbm is not active",
275
+ error_data=transfer_data_to_json_str_to_data(api_auth_data.model_dump())
276
+ )
352
277
 
353
278
  return async_func
@@ -11,7 +11,6 @@ from arpakitlib.ar_datetime_util import now_utc_dt
11
11
  from arpakitlib.ar_dict_util import combine_dicts
12
12
  from arpakitlib.ar_exception_util import exception_to_traceback_str
13
13
  from arpakitlib.ar_func_util import raise_if_not_async_func, is_async_func, is_sync_func
14
- from arpakitlib.ar_json_util import transfer_data_to_json_str
15
14
  from project.api.const import APIErrorCodes
16
15
  from project.api.exception import APIException
17
16
  from project.api.response import APIJSONResponse
@@ -175,7 +174,7 @@ def logging_func_before_in_api_exception_handler(
175
174
  ):
176
175
  return
177
176
 
178
- _logger.error(transfer_data_to_json_str(error_common_so.model_dump()), exc_info=False)
177
+ _logger.exception(exception)
179
178
 
180
179
  return func
181
180
 
@@ -1,6 +1,8 @@
1
1
  import fastapi
2
2
  from fastapi import APIRouter
3
3
 
4
+ from project.api.auth import require_user_token_dbm_api_middleware, require_api_key_dbm_api_middleware, APIAuthData, \
5
+ api_auth
4
6
  from project.api.schema.out.common.error import ErrorCommonSO
5
7
  from project.api.schema.out.common.raw_data import RawDataCommonSO
6
8
  from project.util.arpakitlib_project_template import get_arpakitlib_project_template_info
@@ -17,7 +19,11 @@ api_router = APIRouter()
17
19
  async def _(
18
20
  *,
19
21
  request: fastapi.requests.Request,
20
- response: fastapi.responses.Response
22
+ response: fastapi.responses.Response,
23
+ api_auth_data: APIAuthData = fastapi.Depends(api_auth(middlewares=[
24
+ require_api_key_dbm_api_middleware(require_active=True),
25
+ require_user_token_dbm_api_middleware(require_active=True)
26
+ ]))
21
27
  ):
22
28
  arpakitlib_project_template_data = get_arpakitlib_project_template_info()
23
29
  return RawDataCommonSO(data=arpakitlib_project_template_data)
@@ -2,7 +2,8 @@ import fastapi.requests
2
2
  from fastapi import APIRouter
3
3
 
4
4
  from arpakitlib.ar_json_util import transfer_data_to_json_str_to_data
5
- from project.api.auth import APIAuthData, api_auth
5
+ from project.api.auth import APIAuthData, api_auth, require_user_token_dbm_api_middleware, \
6
+ require_api_key_dbm_api_middleware
6
7
  from project.api.schema.out.common.error import ErrorCommonSO
7
8
  from project.api.schema.out.common.raw_data import RawDataCommonSO
8
9
 
@@ -19,12 +20,9 @@ async def _(
19
20
  *,
20
21
  request: fastapi.requests.Request,
21
22
  response: fastapi.responses.Response,
22
- api_auth_data: APIAuthData = fastapi.Depends(api_auth(
23
- require_not_prod_mode=True,
24
- try_find_api_key_dbm_from_sqlalchemy_db=True,
25
- try_find_user_token_dbm_from_sqlalchemy_db=True,
26
- require_api_key_dbm_from_sqlalchemy_db=True,
27
- require_user_token_dbm_from_sqlalchemy_db=True
28
- ))
23
+ api_auth_data: APIAuthData = fastapi.Depends(api_auth(middlewares=[
24
+ require_api_key_dbm_api_middleware(require_active=True),
25
+ require_user_token_dbm_api_middleware(require_active=True)
26
+ ]))
29
27
  ):
30
28
  return RawDataCommonSO(data=transfer_data_to_json_str_to_data(api_auth_data.model_dump()))
@@ -1,3 +1,20 @@
1
1
  from fastapi import APIRouter
2
2
 
3
+ from project.api.router.admin import get_auth_data, get_arpakitlib_project_template_info, raise_fake_error
4
+
3
5
  main_admin_api_router = APIRouter()
6
+
7
+ main_admin_api_router.include_router(
8
+ router=get_arpakitlib_project_template_info.api_router,
9
+ prefix="/get_arpakitlib_project_template_info"
10
+ )
11
+
12
+ main_admin_api_router.include_router(
13
+ router=get_auth_data.api_router,
14
+ prefix="/get_auth_data"
15
+ )
16
+
17
+ main_admin_api_router.include_router(
18
+ router=raise_fake_error.api_router,
19
+ prefix="/raise_fake_error"
20
+ )
@@ -0,0 +1,27 @@
1
+ import fastapi.requests
2
+ from fastapi import APIRouter
3
+
4
+ from project.api.auth import APIAuthData, api_auth, require_user_token_dbm_api_middleware, \
5
+ require_api_key_dbm_api_middleware
6
+ from project.api.schema.out.common.error import ErrorCommonSO
7
+ from project.api.schema.out.common.raw_data import RawDataCommonSO
8
+
9
+ api_router = APIRouter()
10
+
11
+
12
+ @api_router.get(
13
+ path="",
14
+ name="Raise fake error",
15
+ status_code=fastapi.status.HTTP_200_OK,
16
+ response_model=RawDataCommonSO | ErrorCommonSO,
17
+ )
18
+ async def _(
19
+ *,
20
+ request: fastapi.requests.Request,
21
+ response: fastapi.responses.Response,
22
+ api_auth_data: APIAuthData = fastapi.Depends(api_auth(middlewares=[
23
+ require_api_key_dbm_api_middleware(require_active=True),
24
+ require_user_token_dbm_api_middleware(require_active=True)
25
+ ]))
26
+ ):
27
+ raise Exception("fake error")
@@ -1,9 +1,8 @@
1
1
  import fastapi.requests
2
2
  from fastapi import APIRouter
3
3
 
4
- from project.api.auth2 import APIAuthData, api_auth, require_api_key_string_api_middleware, \
5
- require_user_token_string_api_middleware, try_find_api_key_dbm_api_middleware, \
6
- try_find_user_token_dbm_api_middleware
4
+ from project.api.auth import APIAuthData, api_auth, require_api_key_dbm_api_middleware, \
5
+ require_user_token_dbm_api_middleware
7
6
  from project.api.const import APIErrorCodes, APIErrorSpecificationCodes
8
7
  from project.api.schema.out.common.error import ErrorCommonSO
9
8
  from project.api.schema.out.general.errors_info_general import ErrorsInfoGeneralSO
@@ -22,11 +21,8 @@ async def _(
22
21
  request: fastapi.requests.Request,
23
22
  response: fastapi.responses.Response,
24
23
  api_auth_data: APIAuthData = fastapi.Depends(api_auth(middlewares=[
25
- require_api_key_string_api_middleware(),
26
- require_user_token_string_api_middleware(),
27
- try_find_api_key_dbm_api_middleware(),
28
- try_find_user_token_dbm_api_middleware(),
29
-
24
+ require_api_key_dbm_api_middleware(require_active=True),
25
+ require_user_token_dbm_api_middleware(require_active=True)
30
26
  ]))
31
27
  ):
32
28
  return ErrorsInfoGeneralSO(
@@ -1,3 +1,10 @@
1
1
  from fastapi import APIRouter
2
2
 
3
+ from project.api.router.client import get_errors_info
4
+
3
5
  main_client_api_router = APIRouter()
6
+
7
+ main_client_api_router.include_router(
8
+ router=get_errors_info.api_router,
9
+ prefix="/get_errors_info"
10
+ )
@@ -1,6 +1,6 @@
1
1
  from fastapi import APIRouter
2
2
 
3
- from project.api.router.general import healthcheck
3
+ from project.api.router.general import healthcheck, now_utc_datetime
4
4
 
5
5
  main_general_api_router = APIRouter()
6
6
 
@@ -8,3 +8,7 @@ main_general_api_router.include_router(
8
8
  router=healthcheck.api_router,
9
9
  prefix="/healthcheck"
10
10
  )
11
+ main_general_api_router.include_router(
12
+ router=now_utc_datetime.api_router,
13
+ prefix="/now_utc_datetime"
14
+ )
@@ -17,6 +17,6 @@ api_router = APIRouter()
17
17
  async def _(
18
18
  *,
19
19
  request: fastapi.requests.Request,
20
- response: fastapi.responses.Response
20
+ response: fastapi.responses.Response,
21
21
  ):
22
22
  return DatetimeCommonSO.from_datetime(datetime_=now_utc_dt())
@@ -10,7 +10,7 @@ from project.sqlalchemy_db_.sqlalchemy_model import UserDBM
10
10
  class UserDBMSAdminSO(SimpleDBMAdminSO):
11
11
  mail: str | None
12
12
  roles: list[str]
13
- is_enabled: bool
13
+ is_active: bool
14
14
  tg_id: int | None
15
15
  tg_bot_last_action_dt: dt.datetime | None
16
16
  tg_data: dict[str, Any] | None
@@ -7,7 +7,7 @@ from project.sqlalchemy_db_.sqlalchemy_model import UserTokenDBM
7
7
  class UserTokenDBMSAdminSO(SimpleDBMAdminSO):
8
8
  value: str
9
9
  user_id: int
10
- is_enabled: bool
10
+ is_active: bool
11
11
 
12
12
  @classmethod
13
13
  def from_user_token_dbm(cls, *, user_dbm: UserTokenDBM) -> UserTokenDBMSAdminSO:
@@ -84,24 +84,10 @@ class Settings(SimpleSettings):
84
84
 
85
85
  api_init_json_db: bool = False
86
86
 
87
- api_api_keys: list[str] | None = ["1"]
87
+ api_correct_api_keys: list[str] | None = ["1"]
88
88
 
89
- @field_validator("api_api_keys", mode="before")
90
- def validate_api_api_keys(cls, v: Any, validation_info: ValidationInfo, **kwargs) -> list[str] | None:
91
- if isinstance(v, str):
92
- v = [v]
93
- if isinstance(v, int):
94
- v = [str(v)]
95
- if isinstance(v, list):
96
- for i, v_ in enumerate(v):
97
- if isinstance(v_, int):
98
- v[i] = str(v_)
99
- return v
100
-
101
- api_user_tokens: list[str] | None = ["1"]
102
-
103
- @field_validator("api_user_tokens", mode="before")
104
- def validate_api_tokens(cls, v: Any, validation_info: ValidationInfo, **kwargs) -> list[str] | None:
89
+ @field_validator("api_correct_api_keys", mode="before")
90
+ def validate_api_correct_api_keys(cls, v: Any, validation_info: ValidationInfo, **kwargs) -> list[str] | None:
105
91
  if isinstance(v, str):
106
92
  v = [v]
107
93
  if isinstance(v, int):
@@ -35,7 +35,7 @@ class ApiKeyDBM(SimpleDBM):
35
35
  insert_default=generate_default_api_key_value,
36
36
  nullable=False
37
37
  )
38
- is_enabled: Mapped[bool] = mapped_column(
38
+ is_active: Mapped[bool] = mapped_column(
39
39
  sqlalchemy.Boolean,
40
40
  index=True,
41
41
  insert_default=True,
@@ -33,7 +33,7 @@ class UserDBM(SimpleDBM):
33
33
  index=True,
34
34
  nullable=False
35
35
  )
36
- is_enabled: Mapped[bool] = mapped_column(
36
+ is_active: Mapped[bool] = mapped_column(
37
37
  sqlalchemy.Boolean,
38
38
  index=True,
39
39
  insert_default=True,
@@ -25,7 +25,7 @@ class UserTokenDBM(SimpleDBM):
25
25
  index=True,
26
26
  nullable=False
27
27
  )
28
- is_enabled: Mapped[bool] = mapped_column(
28
+ is_active: Mapped[bool] = mapped_column(
29
29
  sqlalchemy.Boolean,
30
30
  index=True,
31
31
  insert_default=True,
@@ -0,0 +1,35 @@
1
+ import asyncio
2
+ import logging
3
+
4
+ from project.core.settings import get_cached_settings
5
+ from project.sqlalchemy_db_.sqlalchemy_db import get_cached_sqlalchemy_db
6
+ from project.sqlalchemy_db_.sqlalchemy_model import ApiKeyDBM
7
+
8
+ _logger = logging.getLogger(__name__)
9
+
10
+
11
+ def make_test_data_1():
12
+ get_cached_settings().raise_if_prod_mode()
13
+ with get_cached_sqlalchemy_db().new_session() as session:
14
+ for i in range(10):
15
+ api_key = ApiKeyDBM(value=str(i))
16
+ session.add(api_key)
17
+ _logger.info(api_key)
18
+ session.commit()
19
+
20
+
21
+ async def async_make_test_data_1():
22
+ get_cached_settings().raise_if_prod_mode()
23
+
24
+
25
+ def __example():
26
+ make_test_data_1()
27
+
28
+
29
+ async def __async_example():
30
+ await async_make_test_data_1()
31
+
32
+
33
+ if __name__ == '__main__':
34
+ __example()
35
+ asyncio.run(__async_example())
@@ -1,12 +1,14 @@
1
1
  import asyncio
2
2
 
3
+ from project.core.settings import get_cached_settings
4
+
3
5
 
4
6
  def make_test_data_1():
5
- pass
7
+ get_cached_settings().raise_if_prod_mode()
6
8
 
7
9
 
8
10
  async def async_make_test_data_1():
9
- pass
11
+ get_cached_settings().raise_if_prod_mode()
10
12
 
11
13
 
12
14
  def __example():
@@ -1,12 +1,14 @@
1
1
  import asyncio
2
2
 
3
+ from project.core.settings import get_cached_settings
4
+
3
5
 
4
6
  def make_test_data_2():
5
- pass
7
+ get_cached_settings().raise_if_prod_mode()
6
8
 
7
9
 
8
10
  async def async_make_test_data_2():
9
- pass
11
+ get_cached_settings().raise_if_prod_mode()
10
12
 
11
13
 
12
14
  def __example():
@@ -1,12 +1,14 @@
1
1
  import asyncio
2
2
 
3
+ from project.core.settings import get_cached_settings
4
+
3
5
 
4
6
  def make_test_data_3():
5
- pass
7
+ get_cached_settings().raise_if_prod_mode()
6
8
 
7
9
 
8
10
  async def async_make_test_data_3():
9
- pass
11
+ get_cached_settings().raise_if_prod_mode()
10
12
 
11
13
 
12
14
  def __example():
@@ -1,12 +1,14 @@
1
1
  import asyncio
2
2
 
3
+ from project.core.settings import get_cached_settings
4
+
3
5
 
4
6
  def make_test_data_4():
5
- pass
7
+ get_cached_settings().raise_if_prod_mode()
6
8
 
7
9
 
8
10
  async def async_make_test_data_4():
9
- pass
11
+ get_cached_settings().raise_if_prod_mode()
10
12
 
11
13
 
12
14
  def __example():
@@ -1,12 +1,14 @@
1
1
  import asyncio
2
2
 
3
+ from project.core.settings import get_cached_settings
4
+
3
5
 
4
6
  def make_test_data_5():
5
- pass
7
+ get_cached_settings().raise_if_prod_mode()
6
8
 
7
9
 
8
10
  async def async_make_test_data_5():
9
- pass
11
+ get_cached_settings().raise_if_prod_mode()
10
12
 
11
13
 
12
14
  def __example():
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: arpakitlib
3
- Version: 1.8.19
3
+ Version: 1.8.20
4
4
  Summary: arpakitlib
5
5
  License: Apache-2.0
6
6
  Keywords: arpakitlib,arpakit,arpakit-company,arpakitcompany,arpakit_company
@@ -78,27 +78,27 @@ arpakitlib/_arpakit_project_template_v_5/project/additional_model/__init__.py,sh
78
78
  arpakitlib/_arpakit_project_template_v_5/project/additional_model/common.py,sha256=XuVbWeesA5fxD0dFPDW8D7NAk0w4RyD5jXPwGOSFchg,233
79
79
  arpakitlib/_arpakit_project_template_v_5/project/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
80
80
  arpakitlib/_arpakit_project_template_v_5/project/api/asgi.py,sha256=ES3YGwNxWUHVyD6e2ii6QkvTyB-vlVmr8_PhfVIXQ4Y,78
81
- arpakitlib/_arpakit_project_template_v_5/project/api/auth.py,sha256=dlYrosfQ-ww1D0U5oma9TXjlTdQVmNEvvTvJtqWWiGY,13867
82
- arpakitlib/_arpakit_project_template_v_5/project/api/auth2.py,sha256=OCQ8zifsio7_4Pa7GGl40rkbcAYHcnCkO6ThF0J3aLg,9206
81
+ arpakitlib/_arpakit_project_template_v_5/project/api/auth.py,sha256=wuiwenDuQ6NFmYbBcui8RJ3Wzgqz85S5Rpnc5ObrZuM,12096
83
82
  arpakitlib/_arpakit_project_template_v_5/project/api/const.py,sha256=J9bqaRRiIc3RLn6SJTvdfDvFrSsM_Ixii9t2M8dA5Jc,433
84
83
  arpakitlib/_arpakit_project_template_v_5/project/api/create_api_app.py,sha256=-taA-OJ69donUlCUIl4tNxjHjRGnjwXl796lThef-uA,2284
85
84
  arpakitlib/_arpakit_project_template_v_5/project/api/event.py,sha256=xKfJ3UnOx_g1s7KNZjWRp0eZbVRTsSlyJhT3wkfwT6k,2414
86
85
  arpakitlib/_arpakit_project_template_v_5/project/api/exception.py,sha256=cNZaI2DacGLl8Hyn1qIfFpVjvQzOQjwXWsVW4auBrCo,1280
87
- arpakitlib/_arpakit_project_template_v_5/project/api/exception_handler.py,sha256=kiQje9yhaqmklYBI-_cp6vL61bWWRbmbo26eaPR_rWU,11415
86
+ arpakitlib/_arpakit_project_template_v_5/project/api/exception_handler.py,sha256=BZ5myTNgruU7q92cM7832PaB4qHa8ooGcZS6CmSaqnQ,11295
88
87
  arpakitlib/_arpakit_project_template_v_5/project/api/openapi_ui.py,sha256=PLhH-W6zDViO-75AGCs8Vq3IoyHChdqwBYAqLvdQN0U,904
89
88
  arpakitlib/_arpakit_project_template_v_5/project/api/response.py,sha256=xZMymP2BuQaRNVWLeIp3UgUUo-MFN8MJnsn9Al4vOb8,1028
90
89
  arpakitlib/_arpakit_project_template_v_5/project/api/router/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
91
90
  arpakitlib/_arpakit_project_template_v_5/project/api/router/admin/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
92
- arpakitlib/_arpakit_project_template_v_5/project/api/router/admin/get_arpakitlib_project_template_info.py,sha256=fV_9T21qRJJ6AlSeFDWLeKnYJ3nKnCWvxFu9gIUc9Wg,723
93
- arpakitlib/_arpakit_project_template_v_5/project/api/router/admin/get_auth_data.py,sha256=W4xlcoCViqMAEOJ5O9UYc4hNVtf3c80tGnV-71WMbLU,1047
94
- arpakitlib/_arpakit_project_template_v_5/project/api/router/admin/main_router.py,sha256=deRK2jKrDmg44ZibSq4RbytGdV4c17J9gQsfZRLDxE0,67
91
+ arpakitlib/_arpakit_project_template_v_5/project/api/router/admin/get_arpakitlib_project_template_info.py,sha256=uN2yJN8NpncyvIOc-D6s9nxftDpA5XwP9ZC6wqI9FZw,1084
92
+ arpakitlib/_arpakit_project_template_v_5/project/api/router/admin/get_auth_data.py,sha256=SWh7P4-D1LSTS0anBEbIxnQI6OV9nymBlqFV5P8h8j4,1007
93
+ arpakitlib/_arpakit_project_template_v_5/project/api/router/admin/main_router.py,sha256=wzlJlKxj-hontW8ckuyqpQvzRKs0clpSAuwpXpFiaAQ,545
94
+ arpakitlib/_arpakit_project_template_v_5/project/api/router/admin/raise_fake_error.py,sha256=DNRWLRCmGoqqdjnm_zjJmFkClwyEzxpZJTT74vH_TrQ,879
95
95
  arpakitlib/_arpakit_project_template_v_5/project/api/router/client/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
96
- arpakitlib/_arpakit_project_template_v_5/project/api/router/client/get_errors_info.py,sha256=t1sQkVh3WD-8B1RtoXhA-XdDFLB03yBCMv7D-Gzxe20,1266
97
- arpakitlib/_arpakit_project_template_v_5/project/api/router/client/main_router.py,sha256=NVpUXEp1MRkISWTWbYDcgoiqARbzwzhUUEiUtO_ij5s,68
98
- arpakitlib/_arpakit_project_template_v_5/project/api/router/client/now_utc_datetime.py,sha256=II82zoa1LWbSGkn8YMqzZZpkfNgWxEClT2qrrWyzM4Q,590
96
+ arpakitlib/_arpakit_project_template_v_5/project/api/router/client/get_errors_info.py,sha256=uG5skKLpYbrXAlHu8MO8pjIHI9dIvYaL8kfTPW4iEIU,1101
97
+ arpakitlib/_arpakit_project_template_v_5/project/api/router/client/main_router.py,sha256=MFYUoxo0lal7__1B7wf1NT5RhJfVtK5rqp7SYix6AaY,234
99
98
  arpakitlib/_arpakit_project_template_v_5/project/api/router/general/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
100
99
  arpakitlib/_arpakit_project_template_v_5/project/api/router/general/healthcheck.py,sha256=xQNMi81IaroNE2H3LvYNUYV6X1dcGSeS2kAUSvGEcWA,523
101
- arpakitlib/_arpakit_project_template_v_5/project/api/router/general/main_router.py,sha256=cBkG92B4LD4I5TmnQdG3x81n-_9hydRzQMgO4yhv8Cs,225
100
+ arpakitlib/_arpakit_project_template_v_5/project/api/router/general/main_router.py,sha256=OPKujYKPInDozmfZrffQnMGtdwyxMBQv1k2f-LttMDY,356
101
+ arpakitlib/_arpakit_project_template_v_5/project/api/router/general/now_utc_datetime.py,sha256=4On6HXmhUuseuijWIIxuuzxZW1iHjnN_WsKQA8qdMsM,591
102
102
  arpakitlib/_arpakit_project_template_v_5/project/api/router/main_router.py,sha256=Y-PPHWbLoICn0O8NRdx49f7ifEw2uN_QIRwfIseo0J0,615
103
103
  arpakitlib/_arpakit_project_template_v_5/project/api/schema/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
104
104
  arpakitlib/_arpakit_project_template_v_5/project/api/schema/common.py,sha256=DX6Yz63JHoNlgmZnpss2PuRgEtBh3PPlxM6wImYLpXo,718
@@ -115,8 +115,8 @@ arpakitlib/_arpakit_project_template_v_5/project/api/schema/out/admin/__init__.p
115
115
  arpakitlib/_arpakit_project_template_v_5/project/api/schema/out/admin/common.py,sha256=i_qLlACMT7XKB4liOEG1PTYkGIL0IDNHoP2Ioh_Xugw,181
116
116
  arpakitlib/_arpakit_project_template_v_5/project/api/schema/out/admin/operation.py,sha256=SrRo1HqugMGDYnc0NUTzHzoMfNdtRzd1EleejURsx_M,715
117
117
  arpakitlib/_arpakit_project_template_v_5/project/api/schema/out/admin/story_log.py,sha256=GQ5EDbYCDByKVwSJpdfLLULWvjUUhE3vo5c2FdK0HBY,498
118
- arpakitlib/_arpakit_project_template_v_5/project/api/schema/out/admin/user.py,sha256=pae7J75tW9Oj-dCNks1J_9jUTq2TIoRiYPS6MCQuZXE,633
119
- arpakitlib/_arpakit_project_template_v_5/project/api/schema/out/admin/user_token.py,sha256=VhD7OVewrsJmJcNG7Uzm29Dn6pDpsAa3X19-FyiXi3k,447
118
+ arpakitlib/_arpakit_project_template_v_5/project/api/schema/out/admin/user.py,sha256=W0g6qHEKqPa4CJvmhzyfUiLzqXLjtTR3OC07UhfdkZc,632
119
+ arpakitlib/_arpakit_project_template_v_5/project/api/schema/out/admin/user_token.py,sha256=w7LL2q58aG7zgVDW1D_lUhg4zCJLqJcfXQX4geHSPXw,446
120
120
  arpakitlib/_arpakit_project_template_v_5/project/api/schema/out/client/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
121
121
  arpakitlib/_arpakit_project_template_v_5/project/api/schema/out/client/common.py,sha256=hi0ybvowgARVEQaD0V8JYxUM5f4gqaJ6U7FlLQCxABE,182
122
122
  arpakitlib/_arpakit_project_template_v_5/project/api/schema/out/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -138,7 +138,7 @@ arpakitlib/_arpakit_project_template_v_5/project/core/const.py,sha256=hgiiPIYL95
138
138
  arpakitlib/_arpakit_project_template_v_5/project/core/dump_file_storage_in_dir.py,sha256=u3-vStMGaseMsRLuJmQK04UDhaez9vw6o5jyHb1fwNg,617
139
139
  arpakitlib/_arpakit_project_template_v_5/project/core/jinja2_templates.py,sha256=jCNLaBauGC7YNvZdTLNHuPp7hmRGt94O23Skg6ewo7o,352
140
140
  arpakitlib/_arpakit_project_template_v_5/project/core/media_file_storage_in_dir.py,sha256=fMofTsfJtA8pp5lEUhucEUu3PBsmj-elaRZzExDsdLI,623
141
- arpakitlib/_arpakit_project_template_v_5/project/core/settings.py,sha256=qvoEDtaNO27fEBMHgOLgale9ACd9m6_2ZQpXdcCEI0g,6359
141
+ arpakitlib/_arpakit_project_template_v_5/project/core/settings.py,sha256=jGZSy5VNfYaoq3tiUywHV8Nlx1_Vsw2Fml22bc3UUiQ,5905
142
142
  arpakitlib/_arpakit_project_template_v_5/project/core/util.py,sha256=1ha9UrguVPsTSjoMHhVZVCD0_mNBfhIDGEvcG1nA4Zw,667
143
143
  arpakitlib/_arpakit_project_template_v_5/project/json_db/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
144
144
  arpakitlib/_arpakit_project_template_v_5/project/json_db/json_db.py,sha256=tBML-z4Y7uY8f_0ggcxvlDNt15Sf93Jr_OUeHwWxqOA,724
@@ -203,19 +203,20 @@ arpakitlib/_arpakit_project_template_v_5/project/sqlalchemy_db_/__init__.py,sha2
203
203
  arpakitlib/_arpakit_project_template_v_5/project/sqlalchemy_db_/const.py,sha256=dcvj5C9E2F2KCsGZPBBncQf_EvVJAC1qQgnyD8P4ZEw,6
204
204
  arpakitlib/_arpakit_project_template_v_5/project/sqlalchemy_db_/sqlalchemy_db.py,sha256=1y3FaMFzm_5UM2poqtBve_UP_mh1vjs--krq6yO8PsA,742
205
205
  arpakitlib/_arpakit_project_template_v_5/project/sqlalchemy_db_/sqlalchemy_model/__init__.py,sha256=btSjCQ7RJqomeXzYs9HePCu1dZHs0z6-RuboYKG89_8,598
206
- arpakitlib/_arpakit_project_template_v_5/project/sqlalchemy_db_/sqlalchemy_model/api_key.py,sha256=w53wMkQUQjuCGBXZWvz0wSaHVJbVP1u_N5sB0jp5nSg,1039
206
+ arpakitlib/_arpakit_project_template_v_5/project/sqlalchemy_db_/sqlalchemy_model/api_key.py,sha256=a-xSHsnE8EkiH9g1ZoxaQQ7Y7q0urIm3SynlGYiSE8E,1038
207
207
  arpakitlib/_arpakit_project_template_v_5/project/sqlalchemy_db_/sqlalchemy_model/common.py,sha256=yK0fFdRYZUpjWl8Vq9S9DKMLBkj9ZT9TXhGyPuR6asU,1876
208
208
  arpakitlib/_arpakit_project_template_v_5/project/sqlalchemy_db_/sqlalchemy_model/operation.py,sha256=ZyK6jRVYM7K_ze2LDaYBwqTP6MkTFjtQMTD-HroX0jg,3293
209
209
  arpakitlib/_arpakit_project_template_v_5/project/sqlalchemy_db_/sqlalchemy_model/story_log.py,sha256=MyXra-PNFrqe9FOjXnDXNYkzX8_A9pbj2uhk1GTPFJ8,1264
210
- arpakitlib/_arpakit_project_template_v_5/project/sqlalchemy_db_/sqlalchemy_model/user.py,sha256=YQO6ZxY71C3PqgmgCqymZZbmkx5fqpgsJ4wV6J5J8eY,2354
211
- arpakitlib/_arpakit_project_template_v_5/project/sqlalchemy_db_/sqlalchemy_model/user_token.py,sha256=HQ-j6vkVdhbsAHO9a43fVcB-ZQrzQkbYilxNC9dFw5I,1014
210
+ arpakitlib/_arpakit_project_template_v_5/project/sqlalchemy_db_/sqlalchemy_model/user.py,sha256=HwFXmlQD9IIFYwGh5wvp0W1RaKqg2nWtjgLFTIsw5ww,2353
211
+ arpakitlib/_arpakit_project_template_v_5/project/sqlalchemy_db_/sqlalchemy_model/user_token.py,sha256=9yGVRC4Ns1TgM7IOaZvbQWuiLYpxDTQKzitokpCGRoQ,1013
212
212
  arpakitlib/_arpakit_project_template_v_5/project/sqlalchemy_db_/util.py,sha256=QSA_nT6aWdtE412-Uj3VTd7yh3dzS4HugDK9FivjTPo,570
213
213
  arpakitlib/_arpakit_project_template_v_5/project/test_data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
214
- arpakitlib/_arpakit_project_template_v_5/project/test_data/make_test_data_1.py,sha256=yRKf6HYZ2do2g7tAUB172nHA_u-yS9cyHhbinahc7sc,285
215
- arpakitlib/_arpakit_project_template_v_5/project/test_data/make_test_data_2.py,sha256=tBhhXKKlSUh_fEYoOvGRuBKUJxPentya1h_6lcd-hk0,285
216
- arpakitlib/_arpakit_project_template_v_5/project/test_data/make_test_data_3.py,sha256=0xV1EWfadkpSIso5gReDsOwdXunhovx14m-FWGCeJj0,285
217
- arpakitlib/_arpakit_project_template_v_5/project/test_data/make_test_data_4.py,sha256=L6c4IUz9Mi2axalGgzVJVqT94lShARVmB596PJ3BCpE,285
218
- arpakitlib/_arpakit_project_template_v_5/project/test_data/make_test_data_5.py,sha256=TN-weOT2xpB0wBkdaJ1F7t8YD63MNN_bZINjPJOfV9g,285
214
+ arpakitlib/_arpakit_project_template_v_5/project/test_data/make_test_api_keys.py,sha256=0T2NXyh2Voy8SmtFNMvvD8HSPVz0OXjsQFDWig5pAAs,834
215
+ arpakitlib/_arpakit_project_template_v_5/project/test_data/make_test_data_1.py,sha256=fioAaw5sWtZdOuHsl1kbVxuU_g0IK8N-gyKlMzVi8FE,416
216
+ arpakitlib/_arpakit_project_template_v_5/project/test_data/make_test_data_2.py,sha256=VcCvxRLA0XnLaQcsaoZkIVV8rTO3uMyLTYoEsdxKtYE,416
217
+ arpakitlib/_arpakit_project_template_v_5/project/test_data/make_test_data_3.py,sha256=9QJTgM4qsJXPgFhfVueQ9vObXr_dAldzP_p8dPO42uA,416
218
+ arpakitlib/_arpakit_project_template_v_5/project/test_data/make_test_data_4.py,sha256=OyU9601WACF7cCpPT33x6CpizNJeQIPDDFezIvEO01A,416
219
+ arpakitlib/_arpakit_project_template_v_5/project/test_data/make_test_data_5.py,sha256=cew0ndlJspNkeQVOS0UPoceg1ARIm5ZFCzytiDIyvbg,416
219
220
  arpakitlib/_arpakit_project_template_v_5/project/tg_bot/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
220
221
  arpakitlib/_arpakit_project_template_v_5/project/tg_bot/blank/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
221
222
  arpakitlib/_arpakit_project_template_v_5/project/tg_bot/blank/admin.py,sha256=RG9YRcOJAkS3Z4VNEnwyTnKj8Xb65gCZWta7NdGdxvU,1008
@@ -340,8 +341,8 @@ arpakitlib/ar_type_util.py,sha256=Cs_tef-Fc5xeyAF54KgISCsP11NHyzIsglm4S3Xx7iM,40
340
341
  arpakitlib/ar_wata_api_client.py,sha256=gdHOqDbuqxhTjVDtRW1DvkRJLdDofCrOq51GTctzLns,242
341
342
  arpakitlib/ar_yookassa_api_client_util.py,sha256=VozuZeCJjmLd1zj2BdC9WfiAQ3XYOrIMsdpNK-AUlm0,5347
342
343
  arpakitlib/ar_zabbix_api_client_util.py,sha256=Q-VR4MvoZ9aHwZeYZr9G3LwN-ANx1T5KFmF6pvPM-9M,6402
343
- arpakitlib-1.8.19.dist-info/LICENSE,sha256=GPEDQMam2r7FSTYqM1mm7aKnxLaWcBotH7UvQtea-ec,11355
344
- arpakitlib-1.8.19.dist-info/METADATA,sha256=Hby8JriGaGGwdPUQ4bNE_OJkSH9Dalc0loZQISb2p6s,3432
345
- arpakitlib-1.8.19.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
346
- arpakitlib-1.8.19.dist-info/entry_points.txt,sha256=36xqR3PJFT2kuwjkM_EqoIy0qFUDPKSm_mJaI7emewE,87
347
- arpakitlib-1.8.19.dist-info/RECORD,,
344
+ arpakitlib-1.8.20.dist-info/LICENSE,sha256=GPEDQMam2r7FSTYqM1mm7aKnxLaWcBotH7UvQtea-ec,11355
345
+ arpakitlib-1.8.20.dist-info/METADATA,sha256=1-ryZ5_8onpKsykVGz1CtFYHmC6CcpHL5Uvx-xLQdLc,3432
346
+ arpakitlib-1.8.20.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
347
+ arpakitlib-1.8.20.dist-info/entry_points.txt,sha256=36xqR3PJFT2kuwjkM_EqoIy0qFUDPKSm_mJaI7emewE,87
348
+ arpakitlib-1.8.20.dist-info/RECORD,,
@@ -1,218 +0,0 @@
1
- from typing import Callable
2
-
3
- import fastapi
4
- import fastapi.exceptions
5
- import fastapi.responses
6
- import fastapi.security
7
- import sqlalchemy
8
- from fastapi import Security
9
- from fastapi.security import APIKeyHeader
10
- from pydantic import BaseModel, ConfigDict
11
-
12
- from arpakitlib.ar_func_util import is_async_func, is_sync_func
13
- from arpakitlib.ar_json_util import transfer_data_to_json_str_to_data
14
- from project.api.const import APIErrorCodes
15
- from project.api.exception import APIException
16
- from project.core.settings import get_cached_settings
17
- from project.sqlalchemy_db_.sqlalchemy_db import get_cached_sqlalchemy_db
18
- from project.sqlalchemy_db_.sqlalchemy_model import ApiKeyDBM, UserTokenDBM
19
-
20
-
21
- class APIAuthData(BaseModel):
22
- model_config = ConfigDict(extra="forbid", arbitrary_types_allowed=True, from_attributes=True)
23
-
24
- api_key_string: str | None = None
25
- user_token_string: str | None = None
26
-
27
- api_key_dbm: ApiKeyDBM | None = None
28
- user_token_dbm: UserTokenDBM | None = None
29
-
30
- prod_mode: bool = False
31
-
32
-
33
- def api_auth(
34
- *,
35
- middlewares: list[Callable] | None = None
36
- ) -> Callable:
37
- if middlewares is None:
38
- middlewares = []
39
-
40
- async def async_func(
41
- *,
42
- ac: fastapi.security.HTTPAuthorizationCredentials | None = fastapi.Security(
43
- fastapi.security.HTTPBearer(auto_error=False)
44
- ),
45
- api_key_string: str | None = Security(
46
- APIKeyHeader(name="apikey", auto_error=False)
47
- ),
48
- request: fastapi.requests.Request
49
- ) -> APIAuthData:
50
-
51
- api_auth_data = APIAuthData(
52
- prod_mode=get_cached_settings().prod_mode
53
- )
54
-
55
- # parse api_key_string
56
-
57
- api_auth_data.api_key_string = api_key_string
58
-
59
- if not api_auth_data.api_key_string and "api_key" in request.headers.keys():
60
- api_auth_data.api_key_string = request.headers["api_key"]
61
- if not api_auth_data.api_key_string and "api-key" in request.headers.keys():
62
- api_auth_data.api_key_string = request.headers["api-key"]
63
- if not api_auth_data.api_key_string and "apikey" in request.headers.keys():
64
- api_auth_data.api_key_string = request.headers["apikey"]
65
- if not api_auth_data.api_key_string and "api_key_string" in request.headers.keys():
66
- api_auth_data.api_key_string = request.headers["api_key_string"]
67
-
68
- if not api_auth_data.api_key_string and "api_key" in request.query_params.keys():
69
- api_auth_data.api_key_string = request.query_params["api_key"]
70
- if not api_auth_data.api_key_string and "api-key" in request.query_params.keys():
71
- api_auth_data.api_key_string = request.query_params["api-key"]
72
- if not api_auth_data.api_key_string and "apikey" in request.query_params.keys():
73
- api_auth_data.api_key_string = request.query_params["apikey"]
74
- if not api_auth_data.api_key_string and "api_key_string" in request.query_params.keys():
75
- api_auth_data.api_key_string = request.query_params["api_key_string"]
76
-
77
- if api_auth_data.api_key_string:
78
- api_auth_data.api_key_string = api_auth_data.api_key_string.strip()
79
- if not api_auth_data.api_key_string:
80
- api_auth_data.api_key_string = None
81
-
82
- # parse user_token_string
83
-
84
- api_auth_data.user_token_string = ac.credentials if ac and ac.credentials and ac.credentials.strip() else None
85
-
86
- if not api_auth_data.user_token_string and "token" in request.headers.keys():
87
- api_auth_data.user_token_string = request.headers["token"]
88
-
89
- if not api_auth_data.user_token_string and "user_token" in request.headers.keys():
90
- api_auth_data.user_token_string = request.headers["user_token"]
91
- if not api_auth_data.user_token_string and "user-token" in request.headers.keys():
92
- api_auth_data.user_token_string = request.headers["user-token"]
93
- if not api_auth_data.user_token_string and "usertoken" in request.headers.keys():
94
- api_auth_data.user_token_string = request.headers["usertoken"]
95
-
96
- if not api_auth_data.user_token_string and "token" in request.query_params.keys():
97
- api_auth_data.user_token_string = request.query_params["token"]
98
-
99
- if not api_auth_data.user_token_string and "user_token" in request.query_params.keys():
100
- api_auth_data.user_token_string = request.query_params["user_token"]
101
- if not api_auth_data.user_token_string and "user-token" in request.query_params.keys():
102
- api_auth_data.user_token_string = request.query_params["user-token"]
103
- if not api_auth_data.user_token_string and "usertoken" in request.query_params.keys():
104
- api_auth_data.user_token_string = request.query_params["usertoken"]
105
-
106
- if api_auth_data.user_token_string:
107
- api_auth_data.user_token_string = api_auth_data.user_token_string.strip()
108
- if not api_auth_data.user_token_string:
109
- api_auth_data.user_token_string = None
110
-
111
- # middlewares
112
-
113
- for middleware in middlewares:
114
- if is_async_func(middleware):
115
- await middleware(
116
- api_auth_data=api_auth_data,
117
- request=request
118
- )
119
- elif is_sync_func(middleware):
120
- middleware(
121
- api_auth_data=api_auth_data,
122
- request=request
123
- )
124
- else:
125
- raise TypeError(f"unknown middleware type, {middleware.__name__}")
126
-
127
- return api_auth_data
128
-
129
- return async_func
130
-
131
-
132
- def require_prod_mode_api_middleware():
133
- def func(*, api_auth_data: APIAuthData, request: fastapi.requests.Request):
134
- if not get_cached_settings().prod_mode:
135
- raise APIException(
136
- status_code=fastapi.status.HTTP_401_UNAUTHORIZED,
137
- error_code=APIErrorCodes.cannot_authorize,
138
- error_description=f"prod_mode={get_cached_settings().prod_mode}",
139
- error_data=transfer_data_to_json_str_to_data(api_auth_data.model_dump())
140
- )
141
-
142
- return func
143
-
144
-
145
- def require_not_prod_mode_api_middleware():
146
- def func(*, api_auth_data: APIAuthData, request: fastapi.requests.Request):
147
- if get_cached_settings().prod_mode:
148
- raise APIException(
149
- status_code=fastapi.status.HTTP_401_UNAUTHORIZED,
150
- error_code=APIErrorCodes.cannot_authorize,
151
- error_description=f"prod_mode={get_cached_settings().prod_mode}",
152
- error_data=transfer_data_to_json_str_to_data(api_auth_data.model_dump())
153
- )
154
-
155
- return func
156
-
157
-
158
- def require_api_key_string_api_middleware():
159
- def func(*, api_auth_data: APIAuthData, request: fastapi.requests.Request):
160
- if api_auth_data.api_key_string is None:
161
- raise APIException(
162
- status_code=fastapi.status.HTTP_401_UNAUTHORIZED,
163
- error_code=APIErrorCodes.cannot_authorize,
164
- error_description="api_key_string is required",
165
- error_data=transfer_data_to_json_str_to_data(api_auth_data.model_dump())
166
- )
167
-
168
- return func
169
-
170
-
171
- def require_user_token_string_api_middleware():
172
- def func(*, api_auth_data: APIAuthData, request: fastapi.requests.Request):
173
- if api_auth_data.user_token_string is None:
174
- raise APIException(
175
- status_code=fastapi.status.HTTP_401_UNAUTHORIZED,
176
- error_code=APIErrorCodes.cannot_authorize,
177
- error_description="user_token_string is required",
178
- error_data=transfer_data_to_json_str_to_data(api_auth_data.model_dump())
179
- )
180
-
181
- return func
182
-
183
-
184
- def try_find_api_key_dbm_api_middleware():
185
- async def async_func(*, api_auth_data: APIAuthData, request: fastapi.requests.Request):
186
- if api_auth_data.api_key_dbm is None:
187
- return
188
- async with get_cached_sqlalchemy_db().new_async_session() as async_session:
189
- api_auth_data.api_key_dbm = await async_session.scalar(
190
- sqlalchemy.select(ApiKeyDBM).where(ApiKeyDBM.value == api_auth_data.api_key_string)
191
- )
192
-
193
- return async_func
194
-
195
-
196
- def try_find_user_token_dbm_api_middleware():
197
- async def async_func(*, api_auth_data: APIAuthData, request: fastapi.requests.Request):
198
- if api_auth_data.user_token_dbm is None:
199
- return
200
- async with get_cached_sqlalchemy_db().new_async_session() as async_session:
201
- api_auth_data.user_token_dbm = await async_session.scalar(
202
- sqlalchemy.select(UserTokenDBM).where(UserTokenDBM.value == api_auth_data.user_token_string)
203
- )
204
-
205
- return async_func
206
-
207
-
208
- def require_api_key_dbm_api_middleware():
209
- async def async_func(*, api_auth_data: APIAuthData, request: fastapi.requests.Request):
210
- if api_auth_data.api_key_dbm is None:
211
- raise APIException(
212
- status_code=fastapi.status.HTTP_401_UNAUTHORIZED,
213
- error_code=APIErrorCodes.cannot_authorize,
214
- error_description="api_key_dbm is required",
215
- error_data=transfer_data_to_json_str_to_data(api_auth_data.model_dump())
216
- )
217
-
218
- return async_func