fiuai-sdk-python 0.6.9__tar.gz → 0.7.1__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.
- {fiuai_sdk_python-0.6.9 → fiuai_sdk_python-0.7.1}/PKG-INFO +1 -1
- {fiuai_sdk_python-0.6.9 → fiuai_sdk_python-0.7.1}/pyproject.toml +1 -1
- {fiuai_sdk_python-0.6.9 → fiuai_sdk_python-0.7.1}/src/fiuai_sdk_python/auth/__init__.py +9 -3
- {fiuai_sdk_python-0.6.9 → fiuai_sdk_python-0.7.1}/src/fiuai_sdk_python/auth/context_mgr.py +57 -3
- fiuai_sdk_python-0.7.1/src/fiuai_sdk_python/auth/helper.py +129 -0
- fiuai_sdk_python-0.6.9/src/fiuai_sdk_python/auth/helper.py +0 -179
- fiuai_sdk_python-0.6.9/src/fiuai_sdk_python/pkg/db/__init__.py +0 -35
- fiuai_sdk_python-0.6.9/src/fiuai_sdk_python/pkg/db/config.py +0 -25
- fiuai_sdk_python-0.6.9/src/fiuai_sdk_python/pkg/db/errors.py +0 -27
- fiuai_sdk_python-0.6.9/src/fiuai_sdk_python/pkg/db/manager.py +0 -439
- fiuai_sdk_python-0.6.9/src/fiuai_sdk_python/pkg/db/utils.py +0 -78
- fiuai_sdk_python-0.6.9/src/fiuai_sdk_python/pkg/vector/__init__.py +0 -23
- fiuai_sdk_python-0.6.9/src/fiuai_sdk_python/pkg/vector/vector.py +0 -853
- {fiuai_sdk_python-0.6.9 → fiuai_sdk_python-0.7.1}/.gitignore +0 -0
- {fiuai_sdk_python-0.6.9 → fiuai_sdk_python-0.7.1}/CHANGELOG.md +0 -0
- {fiuai_sdk_python-0.6.9 → fiuai_sdk_python-0.7.1}/LICENSE +0 -0
- {fiuai_sdk_python-0.6.9 → fiuai_sdk_python-0.7.1}/README.md +0 -0
- {fiuai_sdk_python-0.6.9 → fiuai_sdk_python-0.7.1}/src/fiuai_sdk_python/__init__.py +0 -0
- {fiuai_sdk_python-0.6.9 → fiuai_sdk_python-0.7.1}/src/fiuai_sdk_python/auth/header.py +0 -0
- {fiuai_sdk_python-0.6.9 → fiuai_sdk_python-0.7.1}/src/fiuai_sdk_python/auth/type.py +0 -0
- {fiuai_sdk_python-0.6.9 → fiuai_sdk_python-0.7.1}/src/fiuai_sdk_python/bank.py +0 -0
- {fiuai_sdk_python-0.6.9 → fiuai_sdk_python-0.7.1}/src/fiuai_sdk_python/client.py +0 -0
- {fiuai_sdk_python-0.6.9 → fiuai_sdk_python-0.7.1}/src/fiuai_sdk_python/company.py +0 -0
- {fiuai_sdk_python-0.6.9 → fiuai_sdk_python-0.7.1}/src/fiuai_sdk_python/config.py +0 -0
- {fiuai_sdk_python-0.6.9 → fiuai_sdk_python-0.7.1}/src/fiuai_sdk_python/const.py +0 -0
- {fiuai_sdk_python-0.6.9 → fiuai_sdk_python-0.7.1}/src/fiuai_sdk_python/context.py +0 -0
- {fiuai_sdk_python-0.6.9 → fiuai_sdk_python-0.7.1}/src/fiuai_sdk_python/datatype.py +0 -0
- {fiuai_sdk_python-0.6.9 → fiuai_sdk_python-0.7.1}/src/fiuai_sdk_python/doctype.py +0 -0
- {fiuai_sdk_python-0.6.9 → fiuai_sdk_python-0.7.1}/src/fiuai_sdk_python/error.py +0 -0
- {fiuai_sdk_python-0.6.9 → fiuai_sdk_python-0.7.1}/src/fiuai_sdk_python/examples/fastapi_integration.py +0 -0
- {fiuai_sdk_python-0.6.9 → fiuai_sdk_python-0.7.1}/src/fiuai_sdk_python/http/__init__.py +0 -0
- {fiuai_sdk_python-0.6.9 → fiuai_sdk_python-0.7.1}/src/fiuai_sdk_python/http/client.py +0 -0
- {fiuai_sdk_python-0.6.9 → fiuai_sdk_python-0.7.1}/src/fiuai_sdk_python/item.py +0 -0
- {fiuai_sdk_python-0.6.9 → fiuai_sdk_python-0.7.1}/src/fiuai_sdk_python/perm.py +0 -0
- {fiuai_sdk_python-0.6.9 → fiuai_sdk_python-0.7.1}/src/fiuai_sdk_python/pkg/cache/__init__.py +0 -0
- {fiuai_sdk_python-0.6.9 → fiuai_sdk_python-0.7.1}/src/fiuai_sdk_python/pkg/cache/redis_manager.py +0 -0
- {fiuai_sdk_python-0.6.9 → fiuai_sdk_python-0.7.1}/src/fiuai_sdk_python/profile.py +0 -0
- {fiuai_sdk_python-0.6.9 → fiuai_sdk_python-0.7.1}/src/fiuai_sdk_python/resp.py +0 -0
- {fiuai_sdk_python-0.6.9 → fiuai_sdk_python-0.7.1}/src/fiuai_sdk_python/setup.py +0 -0
- {fiuai_sdk_python-0.6.9 → fiuai_sdk_python-0.7.1}/src/fiuai_sdk_python/type.py +0 -0
- {fiuai_sdk_python-0.6.9 → fiuai_sdk_python-0.7.1}/src/fiuai_sdk_python/util.py +0 -0
- {fiuai_sdk_python-0.6.9 → fiuai_sdk_python-0.7.1}/src/fiuai_sdk_python/utils/__init__.py +0 -0
- {fiuai_sdk_python-0.6.9 → fiuai_sdk_python-0.7.1}/src/fiuai_sdk_python/utils/ids.py +0 -0
- {fiuai_sdk_python-0.6.9 → fiuai_sdk_python-0.7.1}/src/fiuai_sdk_python/utils/logger.py +0 -0
- {fiuai_sdk_python-0.6.9 → fiuai_sdk_python-0.7.1}/src/fiuai_sdk_python/utils/text.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fiuai_sdk_python
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.1
|
|
4
4
|
Summary: FiuAI Python SDK - 企业级AI服务集成开发工具包
|
|
5
5
|
Project-URL: Homepage, https://github.com/fiuai/fiuai-sdk-python
|
|
6
6
|
Project-URL: Documentation, https://github.com/fiuai/fiuai-sdk-python#readme
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from .header import parse_auth_headers, extract_auth_from_request
|
|
2
2
|
from .type import AuthData, AuthHeader
|
|
3
3
|
from .helper import (
|
|
4
|
-
get_auth_data
|
|
4
|
+
get_auth_data,
|
|
5
5
|
get_current_user_id,
|
|
6
6
|
get_current_tenant_id,
|
|
7
7
|
get_current_company,
|
|
@@ -14,19 +14,23 @@ from .context_mgr import (
|
|
|
14
14
|
init_context,
|
|
15
15
|
WorldData,
|
|
16
16
|
get_auth_data_from_context,
|
|
17
|
-
get_auth_data,
|
|
18
17
|
set_auth_data,
|
|
19
18
|
update_auth_data,
|
|
20
19
|
get_world_data,
|
|
20
|
+
set_user_profile_info,
|
|
21
|
+
get_user_profile_info,
|
|
21
22
|
)
|
|
22
23
|
|
|
24
|
+
# 兼容旧用法:从 request 取 auth 时可用 get_auth_data(request) 或 get_auth_data_from_request(request)
|
|
25
|
+
get_auth_data_from_request = get_auth_data
|
|
26
|
+
|
|
23
27
|
__all__ = [
|
|
24
28
|
"parse_auth_headers",
|
|
25
29
|
"extract_auth_from_request",
|
|
26
30
|
"AuthData",
|
|
27
31
|
"AuthHeader",
|
|
28
|
-
"get_auth_data_from_request",
|
|
29
32
|
"get_auth_data",
|
|
33
|
+
"get_auth_data_from_request",
|
|
30
34
|
"get_auth_data_from_context",
|
|
31
35
|
"get_current_user_id",
|
|
32
36
|
"get_current_tenant_id",
|
|
@@ -40,4 +44,6 @@ __all__ = [
|
|
|
40
44
|
"set_auth_data",
|
|
41
45
|
"update_auth_data",
|
|
42
46
|
"get_world_data",
|
|
47
|
+
"set_user_profile_info",
|
|
48
|
+
"get_user_profile_info",
|
|
43
49
|
]
|
|
@@ -8,8 +8,10 @@
|
|
|
8
8
|
"""
|
|
9
9
|
上下文管理:ContextManager、init_context、WorldData,
|
|
10
10
|
以及从当前上下文获取/设置认证数据的 get_auth_data_from_context、set_auth_data、update_auth_data、get_world_data。
|
|
11
|
+
可选:user_profile_info 的 set_user_profile_info / get_user_profile_info(请求级存储,不影响未使用的调用方)。
|
|
11
12
|
"""
|
|
12
13
|
|
|
14
|
+
import contextvars
|
|
13
15
|
import uuid
|
|
14
16
|
import logging
|
|
15
17
|
from typing import Dict, Any, Optional
|
|
@@ -24,6 +26,11 @@ logger = logging.getLogger(__name__)
|
|
|
24
26
|
|
|
25
27
|
_current_context_manager: Optional["ContextManager"] = None
|
|
26
28
|
|
|
29
|
+
# 可选:请求级 UserProfileInfo,仅当调用方 set 时存在,不 set 则 get 为 None
|
|
30
|
+
_user_profile_info: contextvars.ContextVar[Optional[Any]] = contextvars.ContextVar(
|
|
31
|
+
"user_profile_info", default=None
|
|
32
|
+
)
|
|
33
|
+
|
|
27
34
|
|
|
28
35
|
class WorldData(BaseModel):
|
|
29
36
|
"""World 上下文数据模型"""
|
|
@@ -49,6 +56,7 @@ class ContextManager:
|
|
|
49
56
|
world_data: Optional[WorldData] = None,
|
|
50
57
|
event_id: Optional[str] = None,
|
|
51
58
|
task_id: Optional[str] = None,
|
|
59
|
+
user_profile_info: Optional[Any] = None,
|
|
52
60
|
):
|
|
53
61
|
if auth_data and headers:
|
|
54
62
|
raise ValueError("不能同时提供 auth_data 和 headers,请只提供其中一个")
|
|
@@ -60,6 +68,9 @@ class ContextManager:
|
|
|
60
68
|
else:
|
|
61
69
|
self.world_data = WorldData()
|
|
62
70
|
|
|
71
|
+
self._user_profile_info = user_profile_info
|
|
72
|
+
self._user_profile_info_token: Optional[contextvars.Token] = None
|
|
73
|
+
|
|
63
74
|
if auth_data:
|
|
64
75
|
self._context = self._create_context_from_auth_data(auth_data)
|
|
65
76
|
elif headers:
|
|
@@ -87,10 +98,15 @@ class ContextManager:
|
|
|
87
98
|
global _current_context_manager
|
|
88
99
|
_current_context_manager = self
|
|
89
100
|
self._context.__enter__()
|
|
101
|
+
if self._user_profile_info is not None:
|
|
102
|
+
self._user_profile_info_token = _user_profile_info.set(self._user_profile_info)
|
|
90
103
|
logger.debug("Context initialized")
|
|
91
104
|
return self
|
|
92
105
|
|
|
93
106
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
107
|
+
if self._user_profile_info_token is not None:
|
|
108
|
+
_user_profile_info.reset(self._user_profile_info_token)
|
|
109
|
+
self._user_profile_info_token = None
|
|
94
110
|
self._context.__exit__(exc_type, exc_val, exc_tb)
|
|
95
111
|
global _current_context_manager
|
|
96
112
|
_current_context_manager = None
|
|
@@ -124,17 +140,32 @@ def init_context(
|
|
|
124
140
|
world_data: Optional[WorldData] = None,
|
|
125
141
|
event_id: Optional[str] = None,
|
|
126
142
|
task_id: Optional[str] = None,
|
|
143
|
+
user_profile_info: Optional[Any] = None,
|
|
127
144
|
**kwargs: Any,
|
|
128
145
|
) -> ContextManager:
|
|
129
146
|
"""
|
|
130
147
|
初始化上下文,用于后台任务。返回的 ContextManager 必须在 `with` 语句中使用。
|
|
131
148
|
|
|
132
149
|
支持三种方式:1) auth_data 对象 2) headers 字典 3) user_id, auth_tenant_id, current_company。
|
|
150
|
+
trace_id 可从 auth_data.trace_id 或 kwargs["trace_id"](仅方式 3)传入。
|
|
151
|
+
可选 user_profile_info:在 with 块内 get_user_profile_info() 可读。
|
|
133
152
|
"""
|
|
134
153
|
if auth_data:
|
|
135
|
-
return ContextManager(
|
|
154
|
+
return ContextManager(
|
|
155
|
+
auth_data=auth_data,
|
|
156
|
+
world_data=world_data,
|
|
157
|
+
event_id=event_id,
|
|
158
|
+
task_id=task_id,
|
|
159
|
+
user_profile_info=user_profile_info,
|
|
160
|
+
)
|
|
136
161
|
if headers:
|
|
137
|
-
return ContextManager(
|
|
162
|
+
return ContextManager(
|
|
163
|
+
headers=headers,
|
|
164
|
+
world_data=world_data,
|
|
165
|
+
event_id=event_id,
|
|
166
|
+
task_id=task_id,
|
|
167
|
+
user_profile_info=user_profile_info,
|
|
168
|
+
)
|
|
138
169
|
if user_id and auth_tenant_id and current_company:
|
|
139
170
|
auth_data = AuthData(
|
|
140
171
|
user_id=user_id,
|
|
@@ -146,7 +177,13 @@ def init_context(
|
|
|
146
177
|
client=kwargs.get("client", "unknown"),
|
|
147
178
|
channel=kwargs.get("channel", "default"),
|
|
148
179
|
)
|
|
149
|
-
return ContextManager(
|
|
180
|
+
return ContextManager(
|
|
181
|
+
auth_data=auth_data,
|
|
182
|
+
world_data=world_data,
|
|
183
|
+
event_id=event_id,
|
|
184
|
+
task_id=task_id,
|
|
185
|
+
user_profile_info=user_profile_info,
|
|
186
|
+
)
|
|
150
187
|
raise ValueError(
|
|
151
188
|
"必须提供以下之一:"
|
|
152
189
|
"1. auth_data 对象 "
|
|
@@ -235,3 +272,20 @@ def get_world_data() -> Optional[WorldData]:
|
|
|
235
272
|
except Exception as e:
|
|
236
273
|
logger.warning("Failed to get world data: %s", e)
|
|
237
274
|
return None
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
def set_user_profile_info(profile: Optional[Any]) -> None:
|
|
278
|
+
"""
|
|
279
|
+
设置当前请求/上下文内的可选 UserProfileInfo。
|
|
280
|
+
仅当需要 profile 时调用;不调用则 get_user_profile_info() 为 None,不影响其他使用者。
|
|
281
|
+
在 HTTP 请求内由业务在 set_user_context 等入口调用;在 with init_context(...) 内也可通过 init_context(..., user_profile_info=...) 传入。
|
|
282
|
+
"""
|
|
283
|
+
_user_profile_info.set(profile)
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
def get_user_profile_info() -> Optional[Any]:
|
|
287
|
+
"""
|
|
288
|
+
获取当前请求/上下文内的可选 UserProfileInfo。
|
|
289
|
+
未设置时返回 None;类型由调用方约定(如 profile.UserProfileInfo 或 dict)。
|
|
290
|
+
"""
|
|
291
|
+
return _user_profile_info.get()
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# -- coding: utf-8 --
|
|
2
|
+
# Project: auth
|
|
3
|
+
# Created Date: 2025-01-09
|
|
4
|
+
# Author: liming
|
|
5
|
+
# Email: lmlala@aliyun.com
|
|
6
|
+
# Copyright (c) 2025 FiuAI
|
|
7
|
+
|
|
8
|
+
from fastapi import Request, HTTPException
|
|
9
|
+
from typing import Optional, Union, Dict, Literal
|
|
10
|
+
from .type import AuthData
|
|
11
|
+
from .context_mgr import get_auth_data as get_auth_data_from_context
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def get_auth_data(
|
|
15
|
+
request: Optional[Union[Request, Dict[str, str]]] = None,
|
|
16
|
+
engine: Literal["fastapi", "dict"] = "fastapi",
|
|
17
|
+
) -> Optional[AuthData]:
|
|
18
|
+
"""
|
|
19
|
+
从请求或当前上下文中获取认证数据。
|
|
20
|
+
request 为 None 时从当前 RequestContext 解析(FiuaiContextMiddleware + AuthMiddleware 或 init_context 内可用),无上下文时返回 None。
|
|
21
|
+
传入 request 时从 request 取,不存在时抛 HTTPException/ValueError。
|
|
22
|
+
"""
|
|
23
|
+
if request is None:
|
|
24
|
+
return get_auth_data_from_context()
|
|
25
|
+
if engine == "fastapi":
|
|
26
|
+
if not isinstance(request, Request):
|
|
27
|
+
raise TypeError(
|
|
28
|
+
"request must be a FastAPI Request object when engine='fastapi'"
|
|
29
|
+
)
|
|
30
|
+
auth_data = getattr(request.state, "auth_data", None)
|
|
31
|
+
if not auth_data:
|
|
32
|
+
raise HTTPException(
|
|
33
|
+
status_code=401,
|
|
34
|
+
detail={
|
|
35
|
+
"error": "Unauthorized",
|
|
36
|
+
"message": "Authentication data not found",
|
|
37
|
+
"code": "AUTH_NOT_FOUND",
|
|
38
|
+
},
|
|
39
|
+
)
|
|
40
|
+
return auth_data
|
|
41
|
+
if engine == "dict":
|
|
42
|
+
if not isinstance(request, dict):
|
|
43
|
+
raise TypeError("request must be a dict when engine='dict'")
|
|
44
|
+
auth_data = request.get("auth_data")
|
|
45
|
+
if not auth_data:
|
|
46
|
+
raise ValueError("Authentication data not found in request dict")
|
|
47
|
+
return auth_data
|
|
48
|
+
raise ValueError("engine must be either 'fastapi' or 'dict'")
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def get_current_user_id(
|
|
52
|
+
request: Optional[Union[Request, Dict[str, str]]] = None,
|
|
53
|
+
engine: Literal["fastapi", "dict"] = "fastapi",
|
|
54
|
+
) -> Optional[str]:
|
|
55
|
+
"""
|
|
56
|
+
获取当前用户ID。request 为 None 时从当前上下文取;无上下文或未认证时返回 None。
|
|
57
|
+
"""
|
|
58
|
+
auth_data = get_auth_data(request, engine)
|
|
59
|
+
return auth_data.user_id if auth_data else None
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def get_current_tenant_id(
|
|
63
|
+
request: Optional[Union[Request, Dict[str, str]]] = None,
|
|
64
|
+
engine: Literal["fastapi", "dict"] = "fastapi",
|
|
65
|
+
) -> Optional[str]:
|
|
66
|
+
"""
|
|
67
|
+
获取当前租户ID。request 为 None 时从当前上下文取;无上下文或未认证时返回 None。
|
|
68
|
+
"""
|
|
69
|
+
auth_data = get_auth_data(request, engine)
|
|
70
|
+
return auth_data.auth_tenant_id if auth_data else None
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def get_current_company(
|
|
74
|
+
request: Optional[Union[Request, Dict[str, str]]] = None,
|
|
75
|
+
engine: Literal["fastapi", "dict"] = "fastapi",
|
|
76
|
+
) -> Optional[str]:
|
|
77
|
+
"""
|
|
78
|
+
获取当前公司ID。request 为 None 时从当前上下文取;无上下文或未认证时返回 None。
|
|
79
|
+
"""
|
|
80
|
+
auth_data = get_auth_data(request, engine)
|
|
81
|
+
return auth_data.current_company if auth_data else None
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def get_company_unique_no(
|
|
85
|
+
request: Optional[Union[Request, Dict[str, str]]] = None,
|
|
86
|
+
engine: Literal["fastapi", "dict"] = "fastapi",
|
|
87
|
+
) -> Optional[str]:
|
|
88
|
+
"""
|
|
89
|
+
获取当前公司唯一编号。request 为 None 时从当前上下文取;无上下文或未认证时返回 None。
|
|
90
|
+
"""
|
|
91
|
+
auth_data = get_auth_data(request, engine)
|
|
92
|
+
return auth_data.company_unique_no if auth_data else None
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def get_impersonation(
|
|
96
|
+
request: Optional[Union[Request, Dict[str, str]]] = None,
|
|
97
|
+
engine: Literal["fastapi", "dict"] = "fastapi",
|
|
98
|
+
) -> Optional[str]:
|
|
99
|
+
"""
|
|
100
|
+
获取当前代表的租户ID。request 为 None 时从当前上下文取;无上下文或未认证时返回 None。
|
|
101
|
+
"""
|
|
102
|
+
auth_data = get_auth_data(request, engine)
|
|
103
|
+
return auth_data.impersonation if auth_data else None
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def get_current_client(
|
|
107
|
+
request: Optional[Union[Request, Dict[str, str]]] = None,
|
|
108
|
+
engine: Literal["fastapi", "dict"] = "fastapi",
|
|
109
|
+
) -> Optional[str]:
|
|
110
|
+
"""
|
|
111
|
+
获取当前客户端标识。request 为 None 时从当前上下文取;无上下文或未认证时返回 None。
|
|
112
|
+
"""
|
|
113
|
+
auth_data = get_auth_data(request, engine)
|
|
114
|
+
return auth_data.client if auth_data else None
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def is_impersonating(
|
|
118
|
+
request: Optional[Union[Request, Dict[str, str]]] = None,
|
|
119
|
+
engine: Literal["fastapi", "dict"] = "fastapi",
|
|
120
|
+
) -> bool:
|
|
121
|
+
"""
|
|
122
|
+
检查是否正在代表其他租户。request 为 None 时从当前上下文取;无上下文或未认证时返回 False。
|
|
123
|
+
"""
|
|
124
|
+
auth_data = get_auth_data(request, engine)
|
|
125
|
+
if not auth_data:
|
|
126
|
+
return False
|
|
127
|
+
return bool(
|
|
128
|
+
auth_data.impersonation and auth_data.impersonation != auth_data.auth_tenant_id
|
|
129
|
+
)
|
|
@@ -1,179 +0,0 @@
|
|
|
1
|
-
# -- coding: utf-8 --
|
|
2
|
-
# Project: auth
|
|
3
|
-
# Created Date: 2025-01-09
|
|
4
|
-
# Author: liming
|
|
5
|
-
# Email: lmlala@aliyun.com
|
|
6
|
-
# Copyright (c) 2025 FiuAI
|
|
7
|
-
|
|
8
|
-
from fastapi import Request, HTTPException
|
|
9
|
-
from typing import Optional, Union, Dict, Literal
|
|
10
|
-
from .type import AuthData
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
def get_auth_data(
|
|
14
|
-
request: Union[Request, Dict[str, str]],
|
|
15
|
-
engine: Literal["fastapi", "dict"] = "fastapi"
|
|
16
|
-
) -> AuthData:
|
|
17
|
-
"""
|
|
18
|
-
从请求中获取认证数据
|
|
19
|
-
|
|
20
|
-
Args:
|
|
21
|
-
request: FastAPI Request 对象或包含认证数据的字典
|
|
22
|
-
engine: 请求引擎类型,默认为 "fastapi"
|
|
23
|
-
|
|
24
|
-
Returns:
|
|
25
|
-
AuthData: 认证数据
|
|
26
|
-
|
|
27
|
-
Raises:
|
|
28
|
-
HTTPException: 当认证数据不存在时抛出 401 错误(仅限 FastAPI)
|
|
29
|
-
ValueError: 当使用 dict 引擎且认证数据不存在时
|
|
30
|
-
"""
|
|
31
|
-
if engine == "fastapi":
|
|
32
|
-
if not isinstance(request, Request):
|
|
33
|
-
raise TypeError("request must be a FastAPI Request object when engine='fastapi'")
|
|
34
|
-
auth_data = getattr(request.state, 'auth_data', None)
|
|
35
|
-
if not auth_data:
|
|
36
|
-
raise HTTPException(
|
|
37
|
-
status_code=401,
|
|
38
|
-
detail={
|
|
39
|
-
"error": "Unauthorized",
|
|
40
|
-
"message": "Authentication data not found",
|
|
41
|
-
"code": "AUTH_NOT_FOUND"
|
|
42
|
-
}
|
|
43
|
-
)
|
|
44
|
-
return auth_data
|
|
45
|
-
elif engine == "dict":
|
|
46
|
-
if not isinstance(request, dict):
|
|
47
|
-
raise TypeError("request must be a dict when engine='dict'")
|
|
48
|
-
auth_data = request.get('auth_data')
|
|
49
|
-
if not auth_data:
|
|
50
|
-
raise ValueError("Authentication data not found in request dict")
|
|
51
|
-
return auth_data
|
|
52
|
-
else:
|
|
53
|
-
raise ValueError("engine must be either 'fastapi' or 'dict'")
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
def get_current_user_id(
|
|
57
|
-
request: Union[Request, Dict[str, str]],
|
|
58
|
-
engine: Literal["fastapi", "dict"] = "fastapi"
|
|
59
|
-
) -> str:
|
|
60
|
-
"""
|
|
61
|
-
获取当前用户ID
|
|
62
|
-
|
|
63
|
-
Args:
|
|
64
|
-
request: FastAPI Request 对象或包含认证数据的字典
|
|
65
|
-
engine: 请求引擎类型,默认为 "fastapi"
|
|
66
|
-
|
|
67
|
-
Returns:
|
|
68
|
-
str: 用户ID
|
|
69
|
-
"""
|
|
70
|
-
auth_data = get_auth_data(request, engine)
|
|
71
|
-
return auth_data.user_id
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
def get_current_tenant_id(
|
|
75
|
-
request: Union[Request, Dict[str, str]],
|
|
76
|
-
engine: Literal["fastapi", "dict"] = "fastapi"
|
|
77
|
-
) -> str:
|
|
78
|
-
"""
|
|
79
|
-
获取当前租户ID
|
|
80
|
-
|
|
81
|
-
Args:
|
|
82
|
-
request: FastAPI Request 对象或包含认证数据的字典
|
|
83
|
-
engine: 请求引擎类型,默认为 "fastapi"
|
|
84
|
-
|
|
85
|
-
Returns:
|
|
86
|
-
str: 租户ID
|
|
87
|
-
"""
|
|
88
|
-
auth_data = get_auth_data(request, engine)
|
|
89
|
-
return auth_data.auth_tenant_id
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
def get_current_company(
|
|
93
|
-
request: Union[Request, Dict[str, str]],
|
|
94
|
-
engine: Literal["fastapi", "dict"] = "fastapi"
|
|
95
|
-
) -> str:
|
|
96
|
-
"""
|
|
97
|
-
获取当前公司ID
|
|
98
|
-
|
|
99
|
-
Args:
|
|
100
|
-
request: FastAPI Request 对象或包含认证数据的字典
|
|
101
|
-
engine: 请求引擎类型,默认为 "fastapi"
|
|
102
|
-
|
|
103
|
-
Returns:
|
|
104
|
-
str: 公司ID
|
|
105
|
-
"""
|
|
106
|
-
auth_data = get_auth_data(request, engine)
|
|
107
|
-
return auth_data.current_company
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
def get_company_unique_no(
|
|
111
|
-
request: Union[Request, Dict[str, str]],
|
|
112
|
-
engine: Literal["fastapi", "dict"] = "fastapi"
|
|
113
|
-
) -> str:
|
|
114
|
-
"""
|
|
115
|
-
获取当前公司唯一编号
|
|
116
|
-
|
|
117
|
-
Args:
|
|
118
|
-
request: FastAPI Request 对象或包含认证数据的字典
|
|
119
|
-
engine: 请求引擎类型,默认为 "fastapi"
|
|
120
|
-
|
|
121
|
-
Returns:
|
|
122
|
-
str: 公司唯一编号
|
|
123
|
-
"""
|
|
124
|
-
auth_data = get_auth_data(request, engine)
|
|
125
|
-
return auth_data.company_unique_no
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
def get_impersonation(
|
|
129
|
-
request: Union[Request, Dict[str, str]],
|
|
130
|
-
engine: Literal["fastapi", "dict"] = "fastapi"
|
|
131
|
-
) -> str:
|
|
132
|
-
"""
|
|
133
|
-
获取当前代表的租户ID
|
|
134
|
-
|
|
135
|
-
Args:
|
|
136
|
-
request: FastAPI Request 对象或包含认证数据的字典
|
|
137
|
-
engine: 请求引擎类型,默认为 "fastapi"
|
|
138
|
-
|
|
139
|
-
Returns:
|
|
140
|
-
str: 代表的租户ID
|
|
141
|
-
"""
|
|
142
|
-
auth_data = get_auth_data(request, engine)
|
|
143
|
-
return auth_data.impersonation
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
def get_current_client(
|
|
147
|
-
request: Union[Request, Dict[str, str]],
|
|
148
|
-
engine: Literal["fastapi", "dict"] = "fastapi"
|
|
149
|
-
) -> str:
|
|
150
|
-
"""
|
|
151
|
-
获取当前客户端标识
|
|
152
|
-
|
|
153
|
-
Args:
|
|
154
|
-
request: FastAPI Request 对象或包含认证数据的字典
|
|
155
|
-
engine: 请求引擎类型,默认为 "fastapi"
|
|
156
|
-
|
|
157
|
-
Returns:
|
|
158
|
-
str: 客户端标识
|
|
159
|
-
"""
|
|
160
|
-
auth_data = get_auth_data(request, engine)
|
|
161
|
-
return auth_data.client
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
def is_impersonating(
|
|
165
|
-
request: Union[Request, Dict[str, str]],
|
|
166
|
-
engine: Literal["fastapi", "dict"] = "fastapi"
|
|
167
|
-
) -> bool:
|
|
168
|
-
"""
|
|
169
|
-
检查是否正在代表其他租户
|
|
170
|
-
|
|
171
|
-
Args:
|
|
172
|
-
request: FastAPI Request 对象或包含认证数据的字典
|
|
173
|
-
engine: 请求引擎类型,默认为 "fastapi"
|
|
174
|
-
|
|
175
|
-
Returns:
|
|
176
|
-
bool: 是否正在代表其他租户
|
|
177
|
-
"""
|
|
178
|
-
auth_data = get_auth_data(request, engine)
|
|
179
|
-
return bool(auth_data.impersonation and auth_data.impersonation != auth_data.auth_tenant_id)
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
# -- coding: utf-8 --
|
|
2
|
-
# Project: fiuai-world
|
|
3
|
-
# Created Date: 2025-01-27
|
|
4
|
-
# Author: liming
|
|
5
|
-
# Email: lmlala@aliyun.com
|
|
6
|
-
# Copyright (c) 2025 FiuAI
|
|
7
|
-
|
|
8
|
-
from pkg.db.errors import (
|
|
9
|
-
PostgresError,
|
|
10
|
-
PostgresConnectionError,
|
|
11
|
-
PostgresQueryError,
|
|
12
|
-
PostgresPoolError,
|
|
13
|
-
)
|
|
14
|
-
from pkg.db.config import PostgresConfig
|
|
15
|
-
from pkg.db.manager import (
|
|
16
|
-
PostgresManager,
|
|
17
|
-
postgres_manager,
|
|
18
|
-
)
|
|
19
|
-
from pkg.db.utils import (
|
|
20
|
-
escape_table_name,
|
|
21
|
-
build_frappe_table_name,
|
|
22
|
-
)
|
|
23
|
-
|
|
24
|
-
__all__ = [
|
|
25
|
-
'PostgresManager',
|
|
26
|
-
'PostgresConfig',
|
|
27
|
-
'PostgresError',
|
|
28
|
-
'PostgresConnectionError',
|
|
29
|
-
'PostgresQueryError',
|
|
30
|
-
'PostgresPoolError',
|
|
31
|
-
'postgres_manager',
|
|
32
|
-
'escape_table_name',
|
|
33
|
-
'build_frappe_table_name',
|
|
34
|
-
]
|
|
35
|
-
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
# -- coding: utf-8 --
|
|
2
|
-
# Project: fiuai-world
|
|
3
|
-
# Created Date: 2025-01-27
|
|
4
|
-
# Author: liming
|
|
5
|
-
# Email: lmlala@aliyun.com
|
|
6
|
-
# Copyright (c) 2025 FiuAI
|
|
7
|
-
|
|
8
|
-
from dataclasses import dataclass
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
@dataclass
|
|
12
|
-
class PostgresConfig:
|
|
13
|
-
"""PostgreSQL 配置"""
|
|
14
|
-
host: str
|
|
15
|
-
port: int
|
|
16
|
-
user: str
|
|
17
|
-
password: str
|
|
18
|
-
database: str
|
|
19
|
-
pool_minconn: int = 1 # 连接池最小连接数
|
|
20
|
-
pool_maxconn: int = 10 # 连接池最大连接数
|
|
21
|
-
pool_timeout: int = 30 # 获取连接超时时间(秒)
|
|
22
|
-
connect_timeout: int = 10 # 连接超时时间(秒)
|
|
23
|
-
retry_count: int = 3 # 重试次数
|
|
24
|
-
retry_delay: int = 1 # 重试延迟(秒)
|
|
25
|
-
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
# -- coding: utf-8 --
|
|
2
|
-
# Project: fiuai-world
|
|
3
|
-
# Created Date: 2025-01-27
|
|
4
|
-
# Author: liming
|
|
5
|
-
# Email: lmlala@aliyun.com
|
|
6
|
-
# Copyright (c) 2025 FiuAI
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class PostgresError(Exception):
|
|
10
|
-
"""PostgreSQL 基础错误类"""
|
|
11
|
-
pass
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
class PostgresConnectionError(PostgresError):
|
|
15
|
-
"""PostgreSQL 连接错误"""
|
|
16
|
-
pass
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
class PostgresQueryError(PostgresError):
|
|
20
|
-
"""PostgreSQL 查询错误"""
|
|
21
|
-
pass
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
class PostgresPoolError(PostgresError):
|
|
25
|
-
"""PostgreSQL 连接池错误"""
|
|
26
|
-
pass
|
|
27
|
-
|