nlbone 0.6.10__py3-none-any.whl → 0.6.12__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.
- nlbone/adapters/auth/keycloak.py +72 -2
- nlbone/adapters/db/postgres/query_builder.py +55 -10
- nlbone/adapters/http_clients/uploadchi/uploadchi.py +14 -13
- nlbone/adapters/percolation/connection.py +1 -0
- nlbone/core/ports/auth.py +1 -0
- nlbone/interfaces/api/dependencies/auth.py +13 -5
- {nlbone-0.6.10.dist-info → nlbone-0.6.12.dist-info}/METADATA +2 -1
- {nlbone-0.6.10.dist-info → nlbone-0.6.12.dist-info}/RECORD +11 -11
- {nlbone-0.6.10.dist-info → nlbone-0.6.12.dist-info}/WHEEL +0 -0
- {nlbone-0.6.10.dist-info → nlbone-0.6.12.dist-info}/entry_points.txt +0 -0
- {nlbone-0.6.10.dist-info → nlbone-0.6.12.dist-info}/licenses/LICENSE +0 -0
nlbone/adapters/auth/keycloak.py
CHANGED
|
@@ -1,9 +1,31 @@
|
|
|
1
|
+
import functools
|
|
2
|
+
from datetime import datetime, timezone
|
|
3
|
+
from threading import RLock
|
|
4
|
+
|
|
5
|
+
from cachetools import LRUCache
|
|
1
6
|
from keycloak import KeycloakOpenID
|
|
2
7
|
from keycloak.exceptions import KeycloakAuthenticationError
|
|
3
8
|
|
|
4
|
-
from nlbone.config.settings import Settings, get_settings
|
|
9
|
+
from nlbone.config.settings import Settings, get_settings
|
|
5
10
|
from nlbone.core.ports.auth import AuthService
|
|
6
11
|
|
|
12
|
+
_permissions_cache: LRUCache = LRUCache(maxsize=2048)
|
|
13
|
+
_permissions_lock = RLock()
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _now_ts() -> int:
|
|
17
|
+
return int(datetime.now(timezone.utc).timestamp())
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _ttl_from_decoded(decoded: dict) -> int:
|
|
21
|
+
exp = int(decoded.get("exp", 0))
|
|
22
|
+
ttl = max(1, exp - _now_ts())
|
|
23
|
+
return ttl
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _cache_key(sub: str | None, exp: int | None) -> tuple[str | None, int | None]:
|
|
27
|
+
return sub, exp
|
|
28
|
+
|
|
7
29
|
|
|
8
30
|
class KeycloakAuthService(AuthService):
|
|
9
31
|
def __init__(self, settings: Settings | None = None):
|
|
@@ -14,7 +36,7 @@ class KeycloakAuthService(AuthService):
|
|
|
14
36
|
realm_name=s.KEYCLOAK_REALM_NAME,
|
|
15
37
|
client_secret_key=s.KEYCLOAK_CLIENT_SECRET.get_secret_value().strip(),
|
|
16
38
|
)
|
|
17
|
-
self.bypass =
|
|
39
|
+
self.bypass = s.ENV != 'prod'
|
|
18
40
|
|
|
19
41
|
def has_access(self, token, permissions):
|
|
20
42
|
if self.bypass:
|
|
@@ -29,6 +51,49 @@ class KeycloakAuthService(AuthService):
|
|
|
29
51
|
print(f"Token verification failed: {e}")
|
|
30
52
|
return False
|
|
31
53
|
|
|
54
|
+
def _fetch_permissions_from_keycloak(self, token: str) -> tuple[list[str], dict]:
|
|
55
|
+
permissions = self.keycloak_openid.uma_permissions(token)
|
|
56
|
+
decoded_token = self.keycloak_openid.decode_token(token)
|
|
57
|
+
result: list[str] = []
|
|
58
|
+
for p in permissions or []:
|
|
59
|
+
rsname = p.get("rsname")
|
|
60
|
+
for s in p.get("scopes", []) or []:
|
|
61
|
+
result.append(f"{rsname}#{s}")
|
|
62
|
+
return result, decoded_token
|
|
63
|
+
|
|
64
|
+
def get_permissions(self, token: str) -> list[str]:
|
|
65
|
+
try:
|
|
66
|
+
decoded = self.keycloak_openid.decode_token(token)
|
|
67
|
+
sub = decoded.get("sub")
|
|
68
|
+
exp = decoded.get("exp")
|
|
69
|
+
key = _cache_key(sub, exp)
|
|
70
|
+
|
|
71
|
+
now = _now_ts()
|
|
72
|
+
with _permissions_lock:
|
|
73
|
+
entry = _permissions_cache.get(key)
|
|
74
|
+
if entry is not None:
|
|
75
|
+
perms, exp_ts = entry
|
|
76
|
+
if exp_ts > now:
|
|
77
|
+
return perms
|
|
78
|
+
_permissions_cache.pop(key, None)
|
|
79
|
+
|
|
80
|
+
perms, decoded2 = self._fetch_permissions_from_keycloak(token)
|
|
81
|
+
decoded_final = decoded2 or decoded
|
|
82
|
+
sub_f = decoded_final.get("sub")
|
|
83
|
+
exp_f = int(decoded_final.get("exp") or 0)
|
|
84
|
+
key_f = _cache_key(sub_f, exp_f)
|
|
85
|
+
|
|
86
|
+
with _permissions_lock:
|
|
87
|
+
_permissions_cache[key_f] = (perms, exp_f)
|
|
88
|
+
|
|
89
|
+
return perms
|
|
90
|
+
|
|
91
|
+
except KeycloakAuthenticationError:
|
|
92
|
+
return []
|
|
93
|
+
except Exception as e:
|
|
94
|
+
print(f"Getting permissions failed: {e}")
|
|
95
|
+
return []
|
|
96
|
+
|
|
32
97
|
def verify_token(self, token: str) -> dict | None:
|
|
33
98
|
try:
|
|
34
99
|
result = self.keycloak_openid.introspect(token)
|
|
@@ -76,3 +141,8 @@ class KeycloakAuthService(AuthService):
|
|
|
76
141
|
if not self.is_client_token(token, allowed_clients):
|
|
77
142
|
return False
|
|
78
143
|
return self.has_access(token, permissions)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
@functools.lru_cache(maxsize=1)
|
|
147
|
+
def get_auth_service() -> KeycloakAuthService:
|
|
148
|
+
return KeycloakAuthService()
|
|
@@ -28,6 +28,50 @@ class _InvalidEnum(Exception):
|
|
|
28
28
|
pass
|
|
29
29
|
|
|
30
30
|
|
|
31
|
+
from sqlalchemy.orm import aliased
|
|
32
|
+
from sqlalchemy.inspection import inspect
|
|
33
|
+
from sqlalchemy.orm.attributes import InstrumentedAttribute
|
|
34
|
+
from sqlalchemy.orm.relationships import RelationshipProperty
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _resolve_column_and_joins(entity, query, field_path: str, join_cache: dict[str, Any]):
|
|
38
|
+
parts = [p for p in field_path.split(".") if p]
|
|
39
|
+
if not parts:
|
|
40
|
+
return None, query
|
|
41
|
+
|
|
42
|
+
current_cls_or_alias = entity
|
|
43
|
+
current_path_key_parts: list[str] = []
|
|
44
|
+
|
|
45
|
+
for i, part in enumerate(parts):
|
|
46
|
+
current_path_key_parts.append(part)
|
|
47
|
+
path_key = ".".join(current_path_key_parts)
|
|
48
|
+
|
|
49
|
+
if not hasattr(current_cls_or_alias, part):
|
|
50
|
+
return None, query
|
|
51
|
+
|
|
52
|
+
attr = getattr(current_cls_or_alias, part)
|
|
53
|
+
|
|
54
|
+
prop = getattr(attr, "property", None)
|
|
55
|
+
if isinstance(prop, RelationshipProperty):
|
|
56
|
+
alias = join_cache.get(path_key)
|
|
57
|
+
if alias is None:
|
|
58
|
+
alias = aliased(prop.mapper.class_)
|
|
59
|
+
query = query.outerjoin(alias, attr)
|
|
60
|
+
join_cache[path_key] = alias
|
|
61
|
+
current_cls_or_alias = alias
|
|
62
|
+
continue
|
|
63
|
+
|
|
64
|
+
if isinstance(attr, InstrumentedAttribute):
|
|
65
|
+
if i == len(parts) - 1:
|
|
66
|
+
return attr, query
|
|
67
|
+
else:
|
|
68
|
+
return None, query
|
|
69
|
+
|
|
70
|
+
return None, query
|
|
71
|
+
|
|
72
|
+
return None, query
|
|
73
|
+
|
|
74
|
+
|
|
31
75
|
def _apply_order(pagination: PaginateRequest, entity, query):
|
|
32
76
|
order_clauses = []
|
|
33
77
|
|
|
@@ -112,6 +156,7 @@ def _apply_filters(pagination, entity, query):
|
|
|
112
156
|
return query
|
|
113
157
|
|
|
114
158
|
predicates = []
|
|
159
|
+
join_cache: dict[str, Any] = {}
|
|
115
160
|
|
|
116
161
|
if getattr(pagination, "filters", None):
|
|
117
162
|
for raw_field, value in pagination.filters.items():
|
|
@@ -120,10 +165,10 @@ def _apply_filters(pagination, entity, query):
|
|
|
120
165
|
|
|
121
166
|
field, op_hint = _parse_field_and_op(raw_field)
|
|
122
167
|
|
|
123
|
-
|
|
168
|
+
col, query2 = _resolve_column_and_joins(entity, query, field, join_cache)
|
|
169
|
+
if col is None:
|
|
124
170
|
continue
|
|
125
|
-
|
|
126
|
-
col = getattr(entity, field)
|
|
171
|
+
query = query2
|
|
127
172
|
coltype = getattr(col, "type", None)
|
|
128
173
|
|
|
129
174
|
def coerce(v):
|
|
@@ -259,13 +304,13 @@ def _serialize_item(item: Any, output_cls: OutputType) -> Any:
|
|
|
259
304
|
|
|
260
305
|
|
|
261
306
|
def get_paginated_response(
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
307
|
+
pagination,
|
|
308
|
+
entity,
|
|
309
|
+
session: Session,
|
|
310
|
+
*,
|
|
311
|
+
with_count: bool = True,
|
|
312
|
+
output_cls: Optional[Type] = None,
|
|
313
|
+
eager_options: Optional[Sequence[LoaderOption]] = None,
|
|
269
314
|
) -> dict:
|
|
270
315
|
query = session.query(entity)
|
|
271
316
|
if eager_options:
|
|
@@ -35,11 +35,11 @@ def _filename_from_cd(cd: str | None, fallback: str) -> str:
|
|
|
35
35
|
|
|
36
36
|
class UploadchiClient(FileServicePort):
|
|
37
37
|
def __init__(
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
38
|
+
self,
|
|
39
|
+
token_provider: ClientTokenProvider | None = None,
|
|
40
|
+
base_url: Optional[str] = None,
|
|
41
|
+
timeout_seconds: Optional[float] = None,
|
|
42
|
+
client: httpx.Client | None = None,
|
|
43
43
|
) -> None:
|
|
44
44
|
s = get_settings()
|
|
45
45
|
self._base_url = normalize_https_base(base_url or str(s.UPLOADCHI_BASE_URL))
|
|
@@ -51,7 +51,7 @@ class UploadchiClient(FileServicePort):
|
|
|
51
51
|
self._client.close()
|
|
52
52
|
|
|
53
53
|
def upload_file(
|
|
54
|
-
|
|
54
|
+
self, file_bytes: bytes, filename: str, params: dict[str, Any] | None = None, token: str | None = None
|
|
55
55
|
) -> dict:
|
|
56
56
|
tok = _resolve_token(token)
|
|
57
57
|
files = {"file": (filename, file_bytes)}
|
|
@@ -84,12 +84,12 @@ class UploadchiClient(FileServicePort):
|
|
|
84
84
|
raise UploadchiError(r.status_code, r.text)
|
|
85
85
|
|
|
86
86
|
def list_files(
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
87
|
+
self,
|
|
88
|
+
limit: int = 10,
|
|
89
|
+
offset: int = 0,
|
|
90
|
+
filters: dict[str, Any] | None = None,
|
|
91
|
+
sort: list[tuple[str, str]] | None = None,
|
|
92
|
+
token: str | None = None,
|
|
93
93
|
) -> dict:
|
|
94
94
|
tok = _resolve_token(token)
|
|
95
95
|
q = build_list_query(limit, offset, filters, sort)
|
|
@@ -116,6 +116,7 @@ class UploadchiClient(FileServicePort):
|
|
|
116
116
|
|
|
117
117
|
def delete_file(self, file_id: str, token: str | None = None) -> None:
|
|
118
118
|
tok = _resolve_token(token)
|
|
119
|
-
r = self._client.delete(f"{self._base_url}/{file_id}",
|
|
119
|
+
r = self._client.delete(f"{self._base_url}/{file_id}",
|
|
120
|
+
headers=auth_headers(tok or self._token_provider.get_access_token()))
|
|
120
121
|
if r.status_code not in (204, 200):
|
|
121
122
|
raise UploadchiError(r.status_code, r.text)
|
nlbone/core/ports/auth.py
CHANGED
|
@@ -8,3 +8,4 @@ class AuthService(Protocol):
|
|
|
8
8
|
def get_client_token(self) -> dict | None: ...
|
|
9
9
|
def is_client_token(self, token: str, allowed_clients: set[str] | None = None) -> bool: ...
|
|
10
10
|
def client_has_access(self, token: str, perms: list[str], allowed_clients: set[str] | None = None) -> bool: ...
|
|
11
|
+
def get_permissions(self, token: str) -> list[str]: ...
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import functools
|
|
2
2
|
|
|
3
3
|
from nlbone.adapters.auth import KeycloakAuthService
|
|
4
|
+
from nlbone.adapters.auth.keycloak import get_auth_service
|
|
4
5
|
from nlbone.interfaces.api.exceptions import ForbiddenException, UnauthorizedException
|
|
5
6
|
from nlbone.utils.context import current_request
|
|
6
7
|
|
|
@@ -51,8 +52,10 @@ def has_access(*, permissions=None):
|
|
|
51
52
|
request = current_request()
|
|
52
53
|
if not current_user_id():
|
|
53
54
|
raise UnauthorizedException()
|
|
54
|
-
|
|
55
|
-
|
|
55
|
+
user_permissions = get_auth_service().get_permissions(request.state.token)
|
|
56
|
+
for p in permissions or []:
|
|
57
|
+
if p not in user_permissions:
|
|
58
|
+
raise ForbiddenException(f"Forbidden {permissions}")
|
|
56
59
|
|
|
57
60
|
return func(*args, **kwargs)
|
|
58
61
|
|
|
@@ -79,9 +82,14 @@ def client_or_user_has_access(*, permissions=None, client_permissions=None):
|
|
|
79
82
|
else:
|
|
80
83
|
if not current_user_id():
|
|
81
84
|
raise UnauthorizedException()
|
|
82
|
-
|
|
83
|
-
|
|
85
|
+
|
|
86
|
+
user_permissions = get_auth_service().get_permissions(request.state.token)
|
|
87
|
+
for p in permissions or []:
|
|
88
|
+
if p not in user_permissions:
|
|
89
|
+
raise ForbiddenException(f"Forbidden {permissions}")
|
|
84
90
|
|
|
85
91
|
return func(*args, **kwargs)
|
|
92
|
+
|
|
86
93
|
return wrapper
|
|
87
|
-
|
|
94
|
+
|
|
95
|
+
return decorator
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nlbone
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.12
|
|
4
4
|
Summary: Backbone package for interfaces and infrastructure in Python projects
|
|
5
5
|
Author-email: Amir Hosein Kahkbazzadeh <a.khakbazzadeh@gmail.com>
|
|
6
6
|
License: MIT
|
|
7
7
|
License-File: LICENSE
|
|
8
8
|
Requires-Python: >=3.10
|
|
9
9
|
Requires-Dist: anyio>=4.0
|
|
10
|
+
Requires-Dist: cachetools>=6.2.0
|
|
10
11
|
Requires-Dist: dependency-injector>=4.48.1
|
|
11
12
|
Requires-Dist: elasticsearch==8.14.0
|
|
12
13
|
Requires-Dist: fastapi>=0.116
|
|
@@ -3,7 +3,7 @@ nlbone/container.py,sha256=VPGkfQO0HS4SbQy2ja3HVKyuMjD94p5ZmDPSqYHGhNo,3317
|
|
|
3
3
|
nlbone/types.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
4
|
nlbone/adapters/__init__.py,sha256=NzUmk4XPyp3GJOw7VSE86xkQMZLtG3MrOoXLeoB551M,41
|
|
5
5
|
nlbone/adapters/auth/__init__.py,sha256=hkDHvsFhw_UiOHG9ZSMqjiAhK4wumEforitveSZswVw,42
|
|
6
|
-
nlbone/adapters/auth/keycloak.py,sha256=
|
|
6
|
+
nlbone/adapters/auth/keycloak.py,sha256=ZGWeq9by2onb440kNRm4BdcxnO7N1qDPmg8UUrXrUrQ,4924
|
|
7
7
|
nlbone/adapters/auth/token_provider.py,sha256=vL2Hk6HXnBbpk40Tq1wpqak5QQ7KEQf3nRquT0N8V4Q,1433
|
|
8
8
|
nlbone/adapters/cache/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
9
|
nlbone/adapters/cache/async_redis.py,sha256=vvu5w4ANx0BVRHL95RAMGsD8CcaC-tSBMbCius2cuNc,6212
|
|
@@ -15,7 +15,7 @@ nlbone/adapters/db/postgres/__init__.py,sha256=6JYJH0xZs3aR-zuyMpRhsdzFugmqz8npr
|
|
|
15
15
|
nlbone/adapters/db/postgres/audit.py,sha256=8f5XOuW7_ybJyy_STam1FNzqmZAAVAu7tmMRUkCGJOM,4594
|
|
16
16
|
nlbone/adapters/db/postgres/base.py,sha256=kha9xmklzhuQAK8QEkNBn-mAHq8dUKbOM-3abaBpWmQ,71
|
|
17
17
|
nlbone/adapters/db/postgres/engine.py,sha256=UCegauVB1gvo42ThytYnn5VIcQBwR-5xhcXYFApRFNk,3448
|
|
18
|
-
nlbone/adapters/db/postgres/query_builder.py,sha256=
|
|
18
|
+
nlbone/adapters/db/postgres/query_builder.py,sha256=SNNkmoMuzcuOwxZlTlplAGqJ0mDQevixLOruqHPa8zM,10855
|
|
19
19
|
nlbone/adapters/db/postgres/repository.py,sha256=J_DBE73JhHPYCk90c5-O7lQtZbxDgqjjN9OcWy4Omvs,1660
|
|
20
20
|
nlbone/adapters/db/postgres/schema.py,sha256=NlE7Rr8uXypsw4oWkdZhZwcIBHQEPIpoHLxcUo98i6s,1039
|
|
21
21
|
nlbone/adapters/db/postgres/uow.py,sha256=nRxNpY-WoWHpym-XeZ8VHm0MYvtB9wuopOeNdV_ebk8,2088
|
|
@@ -25,13 +25,13 @@ nlbone/adapters/http_clients/__init__.py,sha256=w-Yr9CLuXMU71N0Ada5HbvP1DB53wqeP
|
|
|
25
25
|
nlbone/adapters/http_clients/pricing/__init__.py,sha256=ElA9NFcAR9u4cqb_w3PPqKU3xGeyjNLQ8veJ0ql2iz0,81
|
|
26
26
|
nlbone/adapters/http_clients/pricing/pricing_service.py,sha256=PDG6CbLg_SL-BsrhNwfyypywcuZIsEyj5mpQGSPH4e4,3300
|
|
27
27
|
nlbone/adapters/http_clients/uploadchi/__init__.py,sha256=uBzEOuVtY22teWW2b36Pitkdk5yVdSqa6xbg22JfTNg,105
|
|
28
|
-
nlbone/adapters/http_clients/uploadchi/uploadchi.py,sha256=
|
|
28
|
+
nlbone/adapters/http_clients/uploadchi/uploadchi.py,sha256=oOkjDA7MMGe7HNl7qgoPbeV_EI5PNIx1yidsxvnkhis,4939
|
|
29
29
|
nlbone/adapters/http_clients/uploadchi/uploadchi_async.py,sha256=PQbVNeaYde5CmgT3vcnQoI1PGeSs9AxHlPFuB8biOmU,4717
|
|
30
30
|
nlbone/adapters/messaging/__init__.py,sha256=UDAwu3s-JQmOZjWz2Nu0SgHhnkbeOhKDH_zLD75oWMY,40
|
|
31
31
|
nlbone/adapters/messaging/event_bus.py,sha256=w-NPwDiPMLFPU_enRQCtfQXOALsXfg31u57R8sG_-1U,781
|
|
32
32
|
nlbone/adapters/messaging/redis.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
33
33
|
nlbone/adapters/percolation/__init__.py,sha256=0h1Bw7FzxgkDIHxeoyQXSfegrhP6VbpYV4QC8njYdRE,38
|
|
34
|
-
nlbone/adapters/percolation/connection.py,sha256=
|
|
34
|
+
nlbone/adapters/percolation/connection.py,sha256=KUlYPFBXyjv_IEt8zgwdNKynl4VnzL7bp-hcll48Z2w,398
|
|
35
35
|
nlbone/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
36
36
|
nlbone/config/logging.py,sha256=Ot6Ctf7EQZlW8YNB-uBdleqI6wixn5fH0Eo6QRgNkQk,4358
|
|
37
37
|
nlbone/config/settings.py,sha256=W3NHZP6yjIyyKiGWNkjlUt_RYFKkcIfMBoKih_z_0Bs,3911
|
|
@@ -47,7 +47,7 @@ nlbone/core/domain/base.py,sha256=5oUfbpaI8juJ28Api8J9IXOSm55VI2bp4QNhA0U8h2Y,12
|
|
|
47
47
|
nlbone/core/domain/events.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
48
48
|
nlbone/core/domain/models.py,sha256=Zn_rwtlzfjOEJZo6HS9M8UsMk-HpMJrHAKn05UA-u2k,1461
|
|
49
49
|
nlbone/core/ports/__init__.py,sha256=gx-Ubj7h-1vvnu56sNnRqmer7HHfW3rX2WLl-0AX5U0,214
|
|
50
|
-
nlbone/core/ports/auth.py,sha256=
|
|
50
|
+
nlbone/core/ports/auth.py,sha256=C-GmUqHNx4bAku6KbW_OTpPXCEfurBWWyDi9KxpTi9M,553
|
|
51
51
|
nlbone/core/ports/cache.py,sha256=8pP_z4ta7PNNG8UiSrEF4xMZRm2wLPxISZvdPt7QnxQ,2351
|
|
52
52
|
nlbone/core/ports/event_bus.py,sha256=_Om1GOOT-F325oV6_LJXtLdx4vu5i7KrpTDD3qPJXU0,325
|
|
53
53
|
nlbone/core/ports/files.py,sha256=7Ov2ITYRpPwwDTZGCeNVISg8e3A9l08jbOgpTImgfK8,1863
|
|
@@ -62,7 +62,7 @@ nlbone/interfaces/api/routers.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hS
|
|
|
62
62
|
nlbone/interfaces/api/schemas.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
63
63
|
nlbone/interfaces/api/dependencies/__init__.py,sha256=rnYRrFVZCfICQrp_PVFlzNg3BeC57yM08wn2DbOHCfk,359
|
|
64
64
|
nlbone/interfaces/api/dependencies/async_auth.py,sha256=bfxgBXhp29WqevjTG4jrdPNR-75APm4jKyHdOOtxnp4,1825
|
|
65
|
-
nlbone/interfaces/api/dependencies/auth.py,sha256=
|
|
65
|
+
nlbone/interfaces/api/dependencies/auth.py,sha256=D3D-UA2fMtEU-pSQNWk4cb3W74rXiz4a8u1reI7Wrkk,3001
|
|
66
66
|
nlbone/interfaces/api/dependencies/db.py,sha256=-UD39J_86UU7ZJs2ZncpdND0yhAG0NeeeALrgSDuuFw,466
|
|
67
67
|
nlbone/interfaces/api/dependencies/uow.py,sha256=QfLEvLYLNWZJQN1k-0q0hBVtUld3D75P4j39q_RjcnE,1181
|
|
68
68
|
nlbone/interfaces/api/middleware/__init__.py,sha256=zbX2vaEAfxRMIYwO2MVY_2O6bqG5H9o7HqGpX14U3Is,158
|
|
@@ -84,8 +84,8 @@ nlbone/utils/context.py,sha256=MmclJ24BG2uvSTg1IK7J-Da9BhVFDQ5ag4Ggs2FF1_w,1600
|
|
|
84
84
|
nlbone/utils/http.py,sha256=UXUoXgQdTRNT08ho8zl-C5ekfDsD8uf-JiMQ323ooqw,872
|
|
85
85
|
nlbone/utils/redactor.py,sha256=-V4HrHmHwPi3Kez587Ek1uJlgK35qGSrwBOvcbw8Jas,1279
|
|
86
86
|
nlbone/utils/time.py,sha256=DjjyQ9GLsfXoT6NK8RDW2rOlJg3e6sF04Jw6PBUrSvg,1268
|
|
87
|
-
nlbone-0.6.
|
|
88
|
-
nlbone-0.6.
|
|
89
|
-
nlbone-0.6.
|
|
90
|
-
nlbone-0.6.
|
|
91
|
-
nlbone-0.6.
|
|
87
|
+
nlbone-0.6.12.dist-info/METADATA,sha256=l0a2XnCXdUv6VvOv_p880moTJFSwVLzLCC6L8NtapMg,2228
|
|
88
|
+
nlbone-0.6.12.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
89
|
+
nlbone-0.6.12.dist-info/entry_points.txt,sha256=CpIL45t5nbhl1dGQPhfIIDfqqak3teK0SxPGBBr7YCk,59
|
|
90
|
+
nlbone-0.6.12.dist-info/licenses/LICENSE,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
91
|
+
nlbone-0.6.12.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|