pixelarraythirdparty 1.3.7__tar.gz → 1.3.9__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. {pixelarraythirdparty-1.3.7 → pixelarraythirdparty-1.3.9}/PKG-INFO +1 -1
  2. {pixelarraythirdparty-1.3.7 → pixelarraythirdparty-1.3.9}/pixelarraythirdparty/__init__.py +1 -7
  3. {pixelarraythirdparty-1.3.7 → pixelarraythirdparty-1.3.9}/pixelarraythirdparty/client.py +1 -1
  4. {pixelarraythirdparty-1.3.7 → pixelarraythirdparty-1.3.9}/pixelarraythirdparty/order/order.py +44 -1
  5. pixelarraythirdparty-1.3.9/pixelarraythirdparty/unified_login/__init__.py +11 -0
  6. pixelarraythirdparty-1.3.9/pixelarraythirdparty/unified_login/unified_login.py +377 -0
  7. {pixelarraythirdparty-1.3.7 → pixelarraythirdparty-1.3.9}/pixelarraythirdparty.egg-info/PKG-INFO +1 -1
  8. {pixelarraythirdparty-1.3.7 → pixelarraythirdparty-1.3.9}/pixelarraythirdparty.egg-info/SOURCES.txt +0 -4
  9. {pixelarraythirdparty-1.3.7 → pixelarraythirdparty-1.3.9}/pyproject.toml +1 -1
  10. pixelarraythirdparty-1.3.7/pixelarraythirdparty/cron/cron.py +0 -80
  11. pixelarraythirdparty-1.3.7/pixelarraythirdparty/custom_events/__init__.py +0 -3
  12. pixelarraythirdparty-1.3.7/pixelarraythirdparty/custom_events/custom_events.py +0 -220
  13. pixelarraythirdparty-1.3.7/pixelarraythirdparty/unified_login/__init__.py +0 -26
  14. pixelarraythirdparty-1.3.7/pixelarraythirdparty/unified_login/unified_login.py +0 -1150
  15. pixelarraythirdparty-1.3.7/pixelarraythirdparty/user/__init__.py +0 -0
  16. {pixelarraythirdparty-1.3.7 → pixelarraythirdparty-1.3.9}/LICENSE +0 -0
  17. {pixelarraythirdparty-1.3.7 → pixelarraythirdparty-1.3.9}/MANIFEST.in +0 -0
  18. {pixelarraythirdparty-1.3.7/pixelarraythirdparty/cron → pixelarraythirdparty-1.3.9/pixelarraythirdparty/feedback}/__init__.py +0 -0
  19. {pixelarraythirdparty-1.3.7 → pixelarraythirdparty-1.3.9}/pixelarraythirdparty/feedback/feedback.py +0 -0
  20. {pixelarraythirdparty-1.3.7/pixelarraythirdparty/feedback → pixelarraythirdparty-1.3.9/pixelarraythirdparty/order}/__init__.py +0 -0
  21. {pixelarraythirdparty-1.3.7/pixelarraythirdparty/order → pixelarraythirdparty-1.3.9/pixelarraythirdparty/product}/__init__.py +0 -0
  22. {pixelarraythirdparty-1.3.7 → pixelarraythirdparty-1.3.9}/pixelarraythirdparty/product/product.py +0 -0
  23. {pixelarraythirdparty-1.3.7/pixelarraythirdparty/product → pixelarraythirdparty-1.3.9/pixelarraythirdparty/project}/__init__.py +0 -0
  24. {pixelarraythirdparty-1.3.7 → pixelarraythirdparty-1.3.9}/pixelarraythirdparty/project/project.py +0 -0
  25. {pixelarraythirdparty-1.3.7 → pixelarraythirdparty-1.3.9}/pixelarraythirdparty/project_dashboard/__init__.py +0 -0
  26. {pixelarraythirdparty-1.3.7 → pixelarraythirdparty-1.3.9}/pixelarraythirdparty/project_dashboard/project_dashboard.py +0 -0
  27. {pixelarraythirdparty-1.3.7/pixelarraythirdparty/project → pixelarraythirdparty-1.3.9/pixelarraythirdparty/support_chat}/__init__.py +0 -0
  28. {pixelarraythirdparty-1.3.7 → pixelarraythirdparty-1.3.9}/pixelarraythirdparty/support_chat/support_chat.py +0 -0
  29. {pixelarraythirdparty-1.3.7/pixelarraythirdparty/support_chat → pixelarraythirdparty-1.3.9/pixelarraythirdparty/user}/__init__.py +0 -0
  30. {pixelarraythirdparty-1.3.7 → pixelarraythirdparty-1.3.9}/pixelarraythirdparty/user/user.py +0 -0
  31. {pixelarraythirdparty-1.3.7 → pixelarraythirdparty-1.3.9}/pixelarraythirdparty.egg-info/dependency_links.txt +0 -0
  32. {pixelarraythirdparty-1.3.7 → pixelarraythirdparty-1.3.9}/pixelarraythirdparty.egg-info/requires.txt +0 -0
  33. {pixelarraythirdparty-1.3.7 → pixelarraythirdparty-1.3.9}/pixelarraythirdparty.egg-info/top_level.txt +0 -0
  34. {pixelarraythirdparty-1.3.7 → pixelarraythirdparty-1.3.9}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pixelarraythirdparty
3
- Version: 1.3.7
3
+ Version: 1.3.9
4
4
  Summary: PixelArray 第三方微服务客户端
5
5
  Author-email: Lu qi <qi.lu@pixelarrayai.com>
6
6
  License-Expression: MIT
@@ -6,13 +6,11 @@ PixelArray 第三方微服务客户端
6
6
  这个库包含了常用的开发工具和服务集成:
7
7
  - order: 订单管理模块和支付模块
8
8
  - product: 产品管理模块
9
- - cron: 定时任务管理模块
10
9
  - user: 用户管理模块
11
10
  - unified_login: 统一登录模块
12
11
  - feedback: 客户反馈模块
13
12
  - project: 项目管理模块
14
13
  - support_chat: 在线客服(临时会话链接)
15
- - custom_events: 自定义事件(新建定义、上报与报表查询)
16
14
  - project_dashboard: 项目看板(按 scope 查询 DNU/DAU/留存)
17
15
  """
18
16
 
@@ -21,27 +19,23 @@ from .support_chat.support_chat import (
21
19
  SupportChatManagerAsync,
22
20
  build_staff_portal_session_url,
23
21
  )
24
- from .custom_events.custom_events import CustomEventsManagerAsync
25
22
  from .project_dashboard.project_dashboard import ProjectDashboardManagerAsync
26
23
 
27
- __version__ = "1.3.7"
24
+ __version__ = "1.3.9"
28
25
  __author__ = "Lu qi"
29
26
  __email__ = "qi.lu@pixelarrayai.com"
30
27
 
31
28
  # 导出主要模块
32
29
  __all__ = [
33
30
  "product",
34
- "cron",
35
31
  "user",
36
32
  "order",
37
33
  "feedback",
38
34
  "project",
39
35
  "support_chat",
40
- "custom_events",
41
36
  "project_dashboard",
42
37
  "FeedbackManagerAsync",
43
38
  "SupportChatManagerAsync",
44
39
  "build_staff_portal_session_url",
45
- "CustomEventsManagerAsync",
46
40
  "ProjectDashboardManagerAsync",
47
41
  ]
@@ -10,7 +10,7 @@ class AsyncClient:
10
10
  parameters:
11
11
  api_key(str): API密钥,用于身份验证
12
12
  """
13
- self.base_url = "https://thirdparty.pixelarrayai.com"
13
+ self.base_url = "https://thirdparty.arraypixelai.com"
14
14
  self.api_key = api_key
15
15
  self.headers = {
16
16
  "Content-Type": "application/json",
@@ -1,3 +1,34 @@
1
+ """
2
+ 订单与支付客户端。
3
+
4
+ 商户业务回调(callback_url)
5
+ --------------------------------
6
+ 创建订单时传入 ``callback_url``(http/https)后,支付成功或退款成功时,
7
+ 本服务会向该地址 **POST** ``Content-Type: application/json``,Body 结构如下。
8
+
9
+ 公共字段(两种事件均包含)::
10
+
11
+ event (str): "order.paid" 或 "order.refunded"
12
+ out_trade_no (str): 商户订单号
13
+ payment_status (str): "PAID" 或 "REFUNDED"
14
+ payment_channel (str): "WECHAT" | "ALIPAY"
15
+ product_id (str|None): 产品 ID
16
+ amount (float|None): 订单金额(元)
17
+ total_fee (int|None): 订单金额(分)
18
+ transaction_id (str|None): 渠道交易号
19
+ timestamp (str): 回调发送时刻,ISO 8601 UTC
20
+
21
+ 支付成功(event="order.paid")额外字段::
22
+
23
+ paid_at (str|None): 支付时间
24
+
25
+ 退款成功(event="order.refunded")额外字段::
26
+
27
+ refunded_at (str|None): 退款时间
28
+
29
+ 幂等:同一状态重复通知不会重复回调。失败时服务端最多重试 2 次(间隔 1 秒)。
30
+ 业务方接口应返回 HTTP 2xx 表示接收成功。
31
+ """
1
32
  from pixelarraythirdparty.client import AsyncClient
2
33
 
3
34
 
@@ -9,6 +40,7 @@ class OrderManagerAsync(AsyncClient):
9
40
  remark: str = None,
10
41
  payment_channel: str = "WECHAT",
11
42
  amount_yuan: float = None,
43
+ callback_url: str = None,
12
44
  ):
13
45
  """
14
46
  description:
@@ -19,6 +51,9 @@ class OrderManagerAsync(AsyncClient):
19
51
  remark(str): 订单备注
20
52
  payment_channel(str): 支付渠道,可选值:"WECHAT"(微信支付)、"ALIPAY"(支付宝支付)
21
53
  amount_yuan(float, optional): 订单金额(元),可变金额产品必填
54
+ callback_url(str, optional): 支付/退款结果业务回调地址(http/https)。
55
+ 支付/退款成功后服务端 POST JSON 至该地址,Body 字段见本模块顶部
56
+ 「商户业务回调(callback_url)」说明。
22
57
  return:
23
58
  data(dict): 订单信息
24
59
  - id(int): 订单ID
@@ -30,6 +65,7 @@ class OrderManagerAsync(AsyncClient):
30
65
  - total_fee(int): 订单金额(分),用于支付接口
31
66
  - body(str): 商品描述
32
67
  - remark(str): 订单备注
68
+ - callback_url(str, optional): 商户业务回调地址
33
69
  - created_at(str): 订单创建时间
34
70
  - updated_at(str): 订单更新时间
35
71
  success(bool): 操作是否成功
@@ -42,6 +78,8 @@ class OrderManagerAsync(AsyncClient):
42
78
  }
43
79
  if amount_yuan is not None:
44
80
  data["amount_yuan"] = amount_yuan
81
+ if callback_url is not None:
82
+ data["callback_url"] = callback_url
45
83
  data, success = await self._request("POST", "/api/orders/create", json=data)
46
84
  if not success:
47
85
  return data, False
@@ -54,6 +92,7 @@ class OrderManagerAsync(AsyncClient):
54
92
  remark: str = None,
55
93
  payment_channel: str = "WECHAT",
56
94
  amount_yuan: float = None,
95
+ callback_url: str = None,
57
96
  ):
58
97
  """
59
98
  description:
@@ -63,8 +102,10 @@ class OrderManagerAsync(AsyncClient):
63
102
  product_id(str): 产品ID
64
103
  body(str): 商品描述
65
104
  remark(str): 订单备注
66
- payment_channel(str): 支付渠道,可选值:"WECHAT"、"ALIPAY"、"PAYPAL"
105
+ payment_channel(str): 支付渠道,可选值:"WECHAT"、"ALIPAY"
67
106
  amount_yuan(float, optional): 订单金额(元),可变金额产品必填
107
+ callback_url(str, optional): 支付/退款结果业务回调地址(http/https)。
108
+ 回调 POST Body 结构见本模块顶部「商户业务回调(callback_url)」说明。
68
109
  return:
69
110
  data(dict): 返回数据
70
111
  - order(dict): 订单信息(字段同 create_order 返回)
@@ -79,6 +120,8 @@ class OrderManagerAsync(AsyncClient):
79
120
  }
80
121
  if amount_yuan is not None:
81
122
  data["amount_yuan"] = amount_yuan
123
+ if callback_url is not None:
124
+ data["callback_url"] = callback_url
82
125
  data, success = await self._request("POST", "/api/orders/create_v2", json=data)
83
126
  if not success:
84
127
  return data, False
@@ -0,0 +1,11 @@
1
+ from .unified_login import (
2
+ OAuth2Login,
3
+ WechatLogin,
4
+ DouyinLogin,
5
+ )
6
+
7
+ __all__ = [
8
+ "OAuth2Login",
9
+ "WechatLogin",
10
+ "DouyinLogin",
11
+ ]
@@ -0,0 +1,377 @@
1
+ import asyncio
2
+ import urllib.parse
3
+ import webbrowser
4
+ from typing import Any, Dict, Optional, Tuple
5
+
6
+ from pixelarraythirdparty.client import AsyncClient
7
+
8
+
9
+ def _normalized_project_name(project_name: Optional[str]) -> Optional[str]:
10
+ if project_name is None:
11
+ return None
12
+ s = str(project_name).strip()
13
+ return s or None
14
+
15
+
16
+ def _auth_url_json(project_name: Optional[str]) -> Optional[Dict[str, Any]]:
17
+ s = _normalized_project_name(project_name)
18
+ if s is None:
19
+ return None
20
+ return {"project_name": s}
21
+
22
+
23
+ class OAuth2Login(AsyncClient):
24
+ """
25
+ 统一的 OAuth2 登录客户端基类
26
+
27
+ 支持所有基于 OAuth2 的第三方登录(Google、微信、GitHub、GitLab、抖音、TikTok等)
28
+ 通过配置不同的端点来支持不同的提供商
29
+
30
+ 使用示例:
31
+ ```
32
+ # 服务端使用场景(推荐)
33
+ oauth2_login = OAuth2Login(
34
+ api_key="your_api_key",
35
+ provider="google" # 支持的提供商:google, wechat, github, gitlab, douyin
36
+ )
37
+ # 1. 获取授权URL
38
+ auth_data, success = await oauth2_login.get_auth_url()
39
+ if success:
40
+ auth_url = auth_data.get("auth_url")
41
+ state = auth_data.get("state")
42
+ # 将auth_url返回给前端,让用户点击授权
43
+ # 2. 等待登录结果(在服务端轮询)
44
+ user_info, success = await oauth2_login.wait_for_login(state, timeout=180)
45
+ print(user_info, success)
46
+ ```
47
+ """
48
+
49
+ # 提供商端点映射
50
+ PROVIDER_ENDPOINTS = {
51
+ "wechat": {
52
+ "auth_url": "/api/unified-login/wechat/auth-url",
53
+ "wait_login": "/api/unified-login/wechat/wait-login",
54
+ },
55
+ "wechat-official": {
56
+ "auth_url": "/api/unified-login/wechat-official/auth-url",
57
+ "wait_login": "/api/unified-login/wechat-official/wait-login",
58
+ },
59
+ "douyin": {
60
+ "auth_url": "/api/unified-login/douyin/auth-url",
61
+ "wait_login": "/api/unified-login/douyin/wait-login",
62
+ },
63
+ }
64
+
65
+ def __init__(
66
+ self,
67
+ api_key: str,
68
+ provider: str,
69
+ login_type: Optional[str] = None,
70
+ project_name: Optional[str] = None,
71
+ ):
72
+ """
73
+ description:
74
+ 初始化OAuth2登录客户端
75
+ parameters:
76
+ api_key(str): API密钥
77
+ provider(str): 提供商名称,可选值:wechat, douyin
78
+ login_type(str, optional): 登录类型,仅对微信有效,可选值:desktop(PC端扫码), mobile(手机端)
79
+ project_name(str, optional): 绑定项目名;不传或空字符串则匿名登录
80
+ """
81
+ super().__init__(api_key)
82
+ self.provider = provider.lower()
83
+ self.login_type = login_type
84
+ self._project_name = project_name
85
+
86
+ # 验证提供商是否支持
87
+ if self.provider not in self.PROVIDER_ENDPOINTS:
88
+ raise ValueError(
89
+ f"不支持的提供商: {provider}。"
90
+ f"支持的提供商: {', '.join(self.PROVIDER_ENDPOINTS.keys())}"
91
+ )
92
+
93
+ # 微信特殊处理:根据login_type选择不同的端点
94
+ if self.provider == "wechat":
95
+ if login_type == "mobile":
96
+ self.provider = "wechat-official"
97
+
98
+ def _get_endpoint(self, endpoint_type: str) -> str:
99
+ """
100
+ description:
101
+ 获取指定类型的端点URL
102
+ parameters:
103
+ endpoint_type(str): 端点类型,可选值:auth_url, wait_login, refresh_token
104
+ return:
105
+ endpoint(str): 端点URL
106
+ """
107
+ endpoints = self.PROVIDER_ENDPOINTS.get(self.provider, {})
108
+ endpoint = endpoints.get(endpoint_type)
109
+ if not endpoint:
110
+ raise ValueError(f"提供商 {self.provider} 不支持 {endpoint_type} 端点")
111
+ return endpoint
112
+
113
+ async def get_auth_url(self) -> Tuple[Optional[Dict[str, str]], bool]:
114
+ """
115
+ description:
116
+ 获取OAuth授权URL(公共方法,供服务端调用)
117
+
118
+ 服务端应该调用此方法获取授权URL,然后将URL返回给前端让用户点击授权。
119
+ 获取到state后,使用wait_for_login方法等待登录结果。
120
+ return:
121
+ auth_data(dict, optional): 授权数据字典,包含auth_url和state
122
+ success(bool): 是否成功
123
+ """
124
+ endpoint = self._get_endpoint("auth_url")
125
+ payload = _auth_url_json(self._project_name)
126
+ if payload:
127
+ data, success = await self._request("POST", endpoint, json=payload)
128
+ else:
129
+ data, success = await self._request("POST", endpoint)
130
+ if not success:
131
+ return data, False
132
+ auth_url = data.get("auth_url")
133
+ if not auth_url:
134
+ return None, False
135
+ return data, True
136
+
137
+ async def wait_for_login(self, state: str, timeout: int = 180) -> Tuple[Dict, bool]:
138
+ """
139
+ description:
140
+ 等待登录结果,轮询检查登录状态(公共方法,供服务端调用)
141
+
142
+ 服务端在用户点击授权后,调用此方法轮询等待登录结果。
143
+ 此方法会持续轮询直到登录成功或超时。
144
+ parameters:
145
+ state(str): 登录状态标识,从get_auth_url返回的auth_data中获取
146
+ timeout(int, optional): 超时时间(秒),默认为180
147
+ return:
148
+ user_info(dict): 用户信息字典
149
+ success(bool): 是否成功
150
+ """
151
+ interval = 2
152
+ total_checks = max(1, timeout // interval) if timeout > 0 else 1
153
+ endpoint = self._get_endpoint("wait_login")
154
+
155
+ for _ in range(total_checks):
156
+ status, response = await self._request_raw(
157
+ "POST",
158
+ endpoint,
159
+ json={"state": state},
160
+ )
161
+
162
+ if status == 200 and response.get("success") is True:
163
+ return response.get("data", {}), True
164
+
165
+ if status in (400, 408):
166
+ break
167
+
168
+ await asyncio.sleep(interval)
169
+
170
+ return {"message": "登录超时或未完成授权"}, False
171
+
172
+
173
+ class WechatLogin(AsyncClient):
174
+ """
175
+ 微信 OAuth2 登录客户端
176
+
177
+ 支持两种登录方式:
178
+ - desktop: PC端扫码登录(使用微信开放平台)
179
+ - mobile: 微信公众号OAuth登录(手机端微信内打开)
180
+
181
+ 使用示例:
182
+ ```
183
+ # 服务端使用场景(推荐)
184
+ wechat = WechatLogin(api_key="your_api_key")
185
+ # PC端扫码登录
186
+ auth_data, success = await wechat.get_auth_url(login_type="desktop")
187
+ if success:
188
+ auth_url = auth_data.get("auth_url")
189
+ state = auth_data.get("state")
190
+ # 将auth_url返回给前端,让用户扫码授权
191
+ # 等待登录结果
192
+ user_info, success = await wechat.wait_for_login(state, timeout=180, login_type="desktop")
193
+ print(user_info, success)
194
+
195
+ # 微信公众号登录(手机端)
196
+ auth_data, success = await wechat.get_auth_url(login_type="mobile")
197
+ if success:
198
+ auth_url = auth_data.get("auth_url")
199
+ state = auth_data.get("state")
200
+ # 将auth_url返回给前端,让用户在微信内打开授权
201
+ # 等待登录结果
202
+ user_info, success = await wechat.wait_for_login(state, timeout=180, login_type="mobile")
203
+ print(user_info, success)
204
+ ```
205
+ """
206
+
207
+ def __init__(self, api_key: str):
208
+ super().__init__(api_key)
209
+
210
+ async def get_auth_url(
211
+ self, login_type: str = "desktop", project_name: Optional[str] = None
212
+ ) -> Tuple[Optional[Dict[str, str]], bool]:
213
+ """
214
+ description:
215
+ 获取微信授权URL(公共方法,供服务端调用)
216
+
217
+ 服务端应该调用此方法获取授权URL,然后将URL返回给前端让用户点击授权。
218
+ 获取到state后,使用wait_for_login方法等待登录结果。
219
+ parameters:
220
+ login_type(str, optional): 登录类型,desktop表示PC端扫码登录,mobile表示微信公众号登录,默认为desktop
221
+ project_name(str, optional): 绑定项目名;不传或空字符串则匿名登录
222
+ return:
223
+ auth_data(dict, optional): 授权数据字典,包含auth_url和state
224
+ success(bool): 是否成功
225
+ """
226
+ if login_type == "mobile":
227
+ # 微信公众号OAuth登录(手机端)
228
+ endpoint = "/api/unified-login/wechat-official/auth-url"
229
+ else:
230
+ # PC端扫码登录
231
+ endpoint = "/api/unified-login/wechat/auth-url"
232
+
233
+ payload = _auth_url_json(project_name)
234
+ if payload:
235
+ data, success = await self._request("POST", endpoint, json=payload)
236
+ else:
237
+ data, success = await self._request("POST", endpoint)
238
+ if not success:
239
+ return data, False
240
+ auth_url = data.get("auth_url")
241
+ if not auth_url:
242
+ return None, False
243
+ return data, True
244
+
245
+ async def wait_for_login(
246
+ self, state: str, timeout: int = 180, login_type: str = "desktop"
247
+ ) -> Tuple[Dict, bool]:
248
+ """
249
+ description:
250
+ 等待微信登录结果,轮询检查登录状态(公共方法,供服务端调用)
251
+
252
+ 服务端在用户点击授权后,调用此方法轮询等待登录结果。
253
+ 此方法会持续轮询直到登录成功或超时。
254
+ parameters:
255
+ state(str): 登录状态标识,从get_auth_url返回的auth_data中获取
256
+ timeout(int, optional): 超时时间(秒),默认为180
257
+ login_type(str, optional): 登录类型,desktop表示PC端扫码登录,mobile表示微信公众号登录,默认为desktop
258
+ return:
259
+ user_info(dict): 用户信息字典
260
+ success(bool): 是否成功
261
+ """
262
+ interval = 2
263
+ total_checks = max(1, timeout // interval) if timeout > 0 else 1
264
+
265
+ # 根据登录类型选择不同的等待接口
266
+ if login_type == "mobile":
267
+ endpoint = "/api/unified-login/wechat-official/wait-login"
268
+ else:
269
+ endpoint = "/api/unified-login/wechat/wait-login"
270
+
271
+ for _ in range(total_checks):
272
+ status, response = await self._request_raw(
273
+ "POST",
274
+ endpoint,
275
+ json={"state": state},
276
+ )
277
+
278
+ if status == 200 and response.get("success") is True:
279
+ return response.get("data", {}), True
280
+
281
+ if status in (400, 408):
282
+ break
283
+
284
+ await asyncio.sleep(interval)
285
+
286
+ return {"message": "登录超时或未完成授权"}, False
287
+
288
+
289
+ class DouyinLogin(AsyncClient):
290
+ """
291
+ 抖音 OAuth2 登录客户端
292
+
293
+ 使用示例:
294
+ ```
295
+ # 服务端使用场景(推荐)
296
+ douyin = DouyinLogin(api_key="your_api_key")
297
+ # 1. 获取授权URL
298
+ auth_data, success = await douyin.get_auth_url()
299
+ if success:
300
+ auth_url = auth_data.get("auth_url")
301
+ state = auth_data.get("state")
302
+ # 将auth_url返回给前端,让用户点击授权
303
+ # 2. 等待登录结果(在服务端轮询)
304
+ user_info, success = await douyin.wait_for_login(state, timeout=180)
305
+ print(user_info, success)
306
+ ```
307
+ """
308
+
309
+ def __init__(self, api_key: str):
310
+ super().__init__(api_key)
311
+
312
+ async def get_auth_url(
313
+ self, project_name: Optional[str] = None
314
+ ) -> Tuple[Optional[Dict[str, str]], bool]:
315
+ """
316
+ description:
317
+ 获取抖音OAuth授权URL(公共方法,供服务端调用)
318
+
319
+ 服务端应该调用此方法获取授权URL,然后将URL返回给前端让用户点击授权。
320
+ 获取到state后,使用wait_for_login方法等待登录结果。
321
+ parameters:
322
+ project_name(str, optional): 绑定项目名;不传或空字符串则匿名登录
323
+ return:
324
+ auth_data(dict, optional): 授权数据字典,包含auth_url和state
325
+ success(bool): 是否成功
326
+ """
327
+ payload = _auth_url_json(project_name)
328
+ if payload:
329
+ data, success = await self._request(
330
+ "POST", "/api/unified-login/douyin/auth-url", json=payload
331
+ )
332
+ else:
333
+ data, success = await self._request(
334
+ "POST", "/api/unified-login/douyin/auth-url"
335
+ )
336
+ if not success:
337
+ return data, False
338
+ auth_url = data.get("auth_url")
339
+ if not auth_url:
340
+ return None, False
341
+ return data, True
342
+
343
+ async def wait_for_login(self, state: str, timeout: int = 180) -> Tuple[Dict, bool]:
344
+ """
345
+ description:
346
+ 等待抖音登录结果,轮询检查登录状态(公共方法,供服务端调用)
347
+
348
+ 服务端在用户点击授权后,调用此方法轮询等待登录结果。
349
+ 此方法会持续轮询直到登录成功或超时。
350
+ parameters:
351
+ state(str): 登录状态标识,从get_auth_url返回的auth_data中获取
352
+ timeout(int, optional): 超时时间(秒),默认为180
353
+ return:
354
+ user_info(dict): 用户信息字典
355
+ success(bool): 是否成功
356
+ """
357
+ interval = 2
358
+ total_checks = max(1, timeout // interval) if timeout > 0 else 1
359
+
360
+ for _ in range(total_checks):
361
+ status, response = await self._request_raw(
362
+ "POST",
363
+ "/api/unified-login/douyin/wait-login",
364
+ json={"state": state},
365
+ )
366
+
367
+ if status == 200 and response.get("success") is True:
368
+ return response.get("data", {}), True
369
+
370
+ if status in (400, 408):
371
+ break
372
+
373
+ await asyncio.sleep(interval)
374
+
375
+ return {"message": "登录超时或未完成授权"}, False
376
+
377
+
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pixelarraythirdparty
3
- Version: 1.3.7
3
+ Version: 1.3.9
4
4
  Summary: PixelArray 第三方微服务客户端
5
5
  Author-email: Lu qi <qi.lu@pixelarrayai.com>
6
6
  License-Expression: MIT
@@ -8,10 +8,6 @@ pixelarraythirdparty.egg-info/SOURCES.txt
8
8
  pixelarraythirdparty.egg-info/dependency_links.txt
9
9
  pixelarraythirdparty.egg-info/requires.txt
10
10
  pixelarraythirdparty.egg-info/top_level.txt
11
- pixelarraythirdparty/cron/__init__.py
12
- pixelarraythirdparty/cron/cron.py
13
- pixelarraythirdparty/custom_events/__init__.py
14
- pixelarraythirdparty/custom_events/custom_events.py
15
11
  pixelarraythirdparty/feedback/__init__.py
16
12
  pixelarraythirdparty/feedback/feedback.py
17
13
  pixelarraythirdparty/order/__init__.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "pixelarraythirdparty"
7
- version = "1.3.7"
7
+ version = "1.3.9"
8
8
  authors = [
9
9
  {name = "Lu qi", email = "qi.lu@pixelarrayai.com"},
10
10
  ]
@@ -1,80 +0,0 @@
1
- from pixelarraythirdparty.client import AsyncClient
2
-
3
-
4
- class CronManagerAsync(AsyncClient):
5
- async def list_cron_task(self):
6
- """
7
- description:
8
- 获取所有配置的定时任务列表,包括任务详情、执行时间、状态等。
9
- return:
10
- data(dict): 定时任务列表信息
11
- - tasks(list): 定时任务列表
12
- - id(str): 任务ID
13
- - name(str): 任务名称
14
- - description(str): 任务描述
15
- - schedule(str): 执行时间
16
- - enabled(bool): 是否启用
17
- - task_name(str): 任务函数名
18
- - module_name(str): 模块名
19
- - function_name(str): 函数名
20
- - file_path(str): 文件路径
21
- - parameters(list): 参数列表
22
- - task_config(dict): 任务配置
23
- - registration_info(dict): 注册信息
24
- - count(int): 任务数量
25
- - timestamp(str): 获取时间
26
- success(bool): 操作是否成功
27
- """
28
- data, success = await self._request("GET", "/api/cron/tasks/scheduled")
29
- if not success:
30
- return data, False
31
- return data, True
32
-
33
- async def get_cron_tasks_detail(self, task_name: str):
34
- """
35
- description:
36
- 根据任务名称获取指定任务的详细信息。
37
- parameters:
38
- task_name(str): 任务名称
39
- return:
40
- data(dict): 任务详细信息
41
- - task_name(str): 任务名称
42
- - module_name(str): 模块名
43
- - function_name(str): 函数名
44
- - file_path(str): 文件路径
45
- - description(str): 任务描述
46
- - parameters(list): 参数列表
47
- - task_config(dict): 任务配置
48
- - registration_info(dict): 注册信息
49
- - timestamp(str): 获取时间
50
- success(bool): 操作是否成功
51
- """
52
- data, success = await self._request("GET", f"/api/cron/tasks/{task_name}")
53
- if not success:
54
- return data, False
55
- return data, True
56
-
57
- async def trigger_cron_task(self, task_name: str, args: list, kwargs: dict):
58
- """
59
- description:
60
- 手动触发指定任务的执行,支持传递参数。
61
- parameters:
62
- task_name(str): 任务名称
63
- args(list): 任务参数列表
64
- kwargs(dict): 任务关键字参数
65
- return:
66
- data(dict): 任务触发信息
67
- - task_id(str): 任务ID
68
- - task_name(str): 任务名称
69
- - status(str): 任务状态,初始为"PENDING"
70
- - message(str): 触发消息
71
- success(bool): 操作是否成功
72
- """
73
- data, success = await self._request(
74
- "POST",
75
- f"/api/cron/tasks/{task_name}/trigger",
76
- json={"args": args, "kwargs": kwargs},
77
- )
78
- if not success:
79
- return data, False
80
- return data, True
@@ -1,3 +0,0 @@
1
- from .custom_events import CustomEventsManagerAsync
2
-
3
- __all__ = ["CustomEventsManagerAsync"]