perk-pushplus-sdk 1.2.2__tar.gz → 1.2.3__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 (67) hide show
  1. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/PKG-INFO +15 -2
  2. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/README.md +14 -1
  3. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/pyproject.toml +1 -1
  4. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus/__init__.py +41 -1
  5. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus/api/__init__.py +4 -0
  6. perk_pushplus_sdk-1.2.3/src/perk_pushplus/api/forward_log.py +25 -0
  7. perk_pushplus_sdk-1.2.3/src/perk_pushplus/api/forward_rule.py +69 -0
  8. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus/client.py +4 -0
  9. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus/config.py +1 -1
  10. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus/enums.py +143 -0
  11. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus/models/__init__.py +28 -0
  12. perk_pushplus_sdk-1.2.3/src/perk_pushplus/models/open_forward.py +247 -0
  13. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus_sdk.egg-info/PKG-INFO +15 -2
  14. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus_sdk.egg-info/SOURCES.txt +3 -0
  15. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/tests/test_enums_and_exceptions.py +10 -0
  16. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/tests/test_open_api.py +64 -0
  17. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/setup.cfg +0 -0
  18. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus/access_key.py +0 -0
  19. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus/api/access_key.py +0 -0
  20. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus/api/base.py +0 -0
  21. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus/api/channel.py +0 -0
  22. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus/api/clawbot.py +0 -0
  23. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus/api/doc.py +0 -0
  24. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus/api/excel.py +0 -0
  25. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus/api/form.py +0 -0
  26. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus/api/friend.py +0 -0
  27. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus/api/image.py +0 -0
  28. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus/api/message.py +0 -0
  29. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus/api/message_token.py +0 -0
  30. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus/api/open_message.py +0 -0
  31. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus/api/pre.py +0 -0
  32. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus/api/qqbot.py +0 -0
  33. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus/api/setting.py +0 -0
  34. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus/api/topic.py +0 -0
  35. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus/api/topic_user.py +0 -0
  36. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus/api/user.py +0 -0
  37. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus/api/webhook.py +0 -0
  38. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus/callback_parser.py +0 -0
  39. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus/exceptions.py +0 -0
  40. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus/http.py +0 -0
  41. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus/models/base.py +0 -0
  42. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus/models/callback.py +0 -0
  43. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus/models/open_access.py +0 -0
  44. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus/models/open_channel.py +0 -0
  45. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus/models/open_clawbot.py +0 -0
  46. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus/models/open_doc.py +0 -0
  47. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus/models/open_form.py +0 -0
  48. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus/models/open_friend.py +0 -0
  49. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus/models/open_image.py +0 -0
  50. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus/models/open_message.py +0 -0
  51. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus/models/open_pre.py +0 -0
  52. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus/models/open_qqbot.py +0 -0
  53. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus/models/open_setting.py +0 -0
  54. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus/models/open_token.py +0 -0
  55. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus/models/open_topic.py +0 -0
  56. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus/models/open_user.py +0 -0
  57. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus/models/open_webhook.py +0 -0
  58. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus/models/send.py +0 -0
  59. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus/multipart.py +0 -0
  60. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus/py.typed +0 -0
  61. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus/rate_limit.py +0 -0
  62. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus_sdk.egg-info/dependency_links.txt +0 -0
  63. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus_sdk.egg-info/requires.txt +0 -0
  64. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/src/perk_pushplus_sdk.egg-info/top_level.txt +0 -0
  65. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/tests/test_image_api.py +0 -0
  66. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/tests/test_message_api.py +0 -0
  67. {perk_pushplus_sdk-1.2.2 → perk_pushplus_sdk-1.2.3}/tests/test_models.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: perk-pushplus-sdk
3
- Version: 1.2.2
3
+ Version: 1.2.3
4
4
  Summary: pushplus(推送加) 官方接口的 Python SDK,覆盖消息发送接口与全部开放接口。
5
5
  Author: perk-net
6
6
  License: Apache-2.0
@@ -35,7 +35,7 @@ Requires-Dist: responses>=0.23; extra == "dev"
35
35
  [pushplus(推送加)](https://www.pushplus.plus) 官方接口的 Python SDK,覆盖 **消息接口** 与 **全部开放接口**。
36
36
 
37
37
  - **消息接口**(`/send`、`/batchSend`):单渠道 + 多渠道发送,含 Builder API。
38
- - **开放接口**(`/api/open/...` 与 `/push/api/open/...`):用户、消息、消息 token、群组、群组用户、好友、webhook、渠道、ClawBot、QQ 机器人、功能设置、预处理信息、图片服务、push 表单、push 文档、push 表格。
38
+ - **开放接口**(`/api/open/...` 与 `/push/api/open/...`):用户、消息、消息 token、群组、群组用户、好友、webhook、渠道、ClawBot、QQ 机器人、功能设置、预处理信息、图片服务、push 表单、push 文档、push 表格、消息规则。
39
39
  - **AccessKey 自动管理**:缓存 + 过期前自动刷新;`code=401` 自动刷新并重试一次。
40
40
  - **本地限流守卫**:命中 `code=900` 后按 token 短路同 token 后续发送,避免被服务端长期封禁。
41
41
  - **回调解析**:`message_complate`、`add_topic_user`、`add_friend` 三类回调统一解析。
@@ -188,6 +188,19 @@ client.setting.change_is_send(1) # 启用发送
188
188
  # 预处理(会员)
189
189
  client.pre.test(...)
190
190
 
191
+ # 消息规则(会员)
192
+ from perk_pushplus import ForwardLogListQuery, ForwardRuleSaveRequest, ForwardVariable
193
+ client.forward_rule.save_setting(1) # 开启,未命中时仍按默认方式推送
194
+ client.forward_rule.add(ForwardRuleSaveRequest(
195
+ ruleName="阿里云监控多渠道",
196
+ tokenId=-1,
197
+ sourceType=1,
198
+ titleTemplate="{{alertName}}",
199
+ variables=[ForwardVariable(varName="alertName", sourceType=3, extractType=1, extractKey="alertName")],
200
+ ))
201
+ rules = client.forward_rule.list()
202
+ logs = client.forward_log.list(ForwardLogListQuery.of(1, 20, match_result=1))
203
+
191
204
  # 图片服务(一行上传到 PushPlus 图床)
192
205
  r = client.image.upload_file("/tmp/logo.png")
193
206
  print(r.url) # 可访问的图片地址
@@ -3,7 +3,7 @@
3
3
  [pushplus(推送加)](https://www.pushplus.plus) 官方接口的 Python SDK,覆盖 **消息接口** 与 **全部开放接口**。
4
4
 
5
5
  - **消息接口**(`/send`、`/batchSend`):单渠道 + 多渠道发送,含 Builder API。
6
- - **开放接口**(`/api/open/...` 与 `/push/api/open/...`):用户、消息、消息 token、群组、群组用户、好友、webhook、渠道、ClawBot、QQ 机器人、功能设置、预处理信息、图片服务、push 表单、push 文档、push 表格。
6
+ - **开放接口**(`/api/open/...` 与 `/push/api/open/...`):用户、消息、消息 token、群组、群组用户、好友、webhook、渠道、ClawBot、QQ 机器人、功能设置、预处理信息、图片服务、push 表单、push 文档、push 表格、消息规则。
7
7
  - **AccessKey 自动管理**:缓存 + 过期前自动刷新;`code=401` 自动刷新并重试一次。
8
8
  - **本地限流守卫**:命中 `code=900` 后按 token 短路同 token 后续发送,避免被服务端长期封禁。
9
9
  - **回调解析**:`message_complate`、`add_topic_user`、`add_friend` 三类回调统一解析。
@@ -156,6 +156,19 @@ client.setting.change_is_send(1) # 启用发送
156
156
  # 预处理(会员)
157
157
  client.pre.test(...)
158
158
 
159
+ # 消息规则(会员)
160
+ from perk_pushplus import ForwardLogListQuery, ForwardRuleSaveRequest, ForwardVariable
161
+ client.forward_rule.save_setting(1) # 开启,未命中时仍按默认方式推送
162
+ client.forward_rule.add(ForwardRuleSaveRequest(
163
+ ruleName="阿里云监控多渠道",
164
+ tokenId=-1,
165
+ sourceType=1,
166
+ titleTemplate="{{alertName}}",
167
+ variables=[ForwardVariable(varName="alertName", sourceType=3, extractType=1, extractKey="alertName")],
168
+ ))
169
+ rules = client.forward_rule.list()
170
+ logs = client.forward_log.list(ForwardLogListQuery.of(1, 20, match_result=1))
171
+
159
172
  # 图片服务(一行上传到 PushPlus 图床)
160
173
  r = client.image.upload_file("/tmp/logo.png")
161
174
  print(r.url) # 可访问的图片地址
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "perk-pushplus-sdk"
7
- version = "1.2.2"
7
+ version = "1.2.3"
8
8
  description = "pushplus(推送加) 官方接口的 Python SDK,覆盖消息发送接口与全部开放接口。"
9
9
  readme = { file = "README.md", content-type = "text/markdown" }
10
10
  requires-python = ">=3.8"
@@ -29,6 +29,13 @@ from .enums import (
29
29
  Channel,
30
30
  ErrorCode,
31
31
  FormStatus,
32
+ ForwardConditionOperator,
33
+ ForwardExtractType,
34
+ ForwardMatchResult,
35
+ ForwardMessageType,
36
+ ForwardMode,
37
+ ForwardSourceType,
38
+ ForwardVarSourceType,
32
39
  SendStatus,
33
40
  ShareLogin,
34
41
  SharePerm,
@@ -63,6 +70,19 @@ from .models import (
63
70
  FormSaveRequest,
64
71
  FormSettings,
65
72
  FormTheme,
73
+ ForwardCondition,
74
+ ForwardConditionItem,
75
+ ForwardLogDetail,
76
+ ForwardLogItem,
77
+ ForwardLogListQuery,
78
+ ForwardRuleDetail,
79
+ ForwardRuleItem,
80
+ ForwardRuleSaveRequest,
81
+ ForwardRuleSetting,
82
+ ForwardRuleTestRequest,
83
+ ForwardRuleTestResult,
84
+ ForwardTarget,
85
+ ForwardVariable,
66
86
  FriendItem,
67
87
  FriendQrCode,
68
88
  FriendBlacklistItem,
@@ -114,7 +134,7 @@ from .models import (
114
134
  )
115
135
  from .rate_limit import RateLimitGuard
116
136
 
117
- __version__ = "1.2.2"
137
+ __version__ = "1.2.3"
118
138
 
119
139
  __all__ = [
120
140
  "__version__",
@@ -139,6 +159,13 @@ __all__ = [
139
159
  "FormStatus",
140
160
  "SharePerm",
141
161
  "ShareLogin",
162
+ "ForwardMode",
163
+ "ForwardSourceType",
164
+ "ForwardVarSourceType",
165
+ "ForwardExtractType",
166
+ "ForwardMatchResult",
167
+ "ForwardConditionOperator",
168
+ "ForwardMessageType",
142
169
  "ApiResponse",
143
170
  "PageQuery",
144
171
  "PageResult",
@@ -212,4 +239,17 @@ __all__ = [
212
239
  "DocContent",
213
240
  "ExcelVo",
214
241
  "ExcelContent",
242
+ "ForwardConditionItem",
243
+ "ForwardCondition",
244
+ "ForwardVariable",
245
+ "ForwardTarget",
246
+ "ForwardRuleItem",
247
+ "ForwardRuleDetail",
248
+ "ForwardRuleSaveRequest",
249
+ "ForwardRuleTestRequest",
250
+ "ForwardRuleTestResult",
251
+ "ForwardRuleSetting",
252
+ "ForwardLogListQuery",
253
+ "ForwardLogItem",
254
+ "ForwardLogDetail",
215
255
  ]
@@ -8,6 +8,8 @@ from .image import ImageApi
8
8
  from .form import FormApi
9
9
  from .doc import DocApi
10
10
  from .excel import ExcelApi
11
+ from .forward_log import ForwardLogApi
12
+ from .forward_rule import ForwardRuleApi
11
13
  from .message import MessageApi
12
14
  from .message_token import MessageTokenApi
13
15
  from .open_message import OpenMessageApi
@@ -40,4 +42,6 @@ __all__ = [
40
42
  "FormApi",
41
43
  "DocApi",
42
44
  "ExcelApi",
45
+ "ForwardRuleApi",
46
+ "ForwardLogApi",
43
47
  ]
@@ -0,0 +1,25 @@
1
+ """开放接口 - 消息规则触发记录(文档「十四. 消息规则接口」第 10、11 节)。"""
2
+ from __future__ import annotations
3
+
4
+ from typing import Optional
5
+
6
+ from ..models import ForwardLogDetail, ForwardLogItem, ForwardLogListQuery, PageResult
7
+ from .base import OpenAbstractApi
8
+
9
+
10
+ class ForwardLogApi(OpenAbstractApi):
11
+ """消息规则触发记录。"""
12
+
13
+ def list(self, query: Optional[ForwardLogListQuery] = None) -> PageResult[ForwardLogItem]:
14
+ body = query if query is not None else ForwardLogListQuery()
15
+ result = self.execute_open(
16
+ "POST", "/api/open/forwardLog/list", body, PageResult[ForwardLogItem]
17
+ )
18
+ return result or PageResult(list=[])
19
+
20
+ def detail(self, log_id: int) -> ForwardLogDetail:
21
+ path = self.append_query("/api/open/forwardLog/detail", {"logId": int(log_id)})
22
+ return self.execute_open("GET", path, None, ForwardLogDetail)
23
+
24
+
25
+ __all__ = ["ForwardLogApi"]
@@ -0,0 +1,69 @@
1
+ """开放接口 - 消息规则(文档「十四. 消息规则接口」)。需开通会员后才能开启。"""
2
+ from __future__ import annotations
3
+
4
+ from typing import Optional
5
+
6
+ from ..models import (
7
+ ForwardRuleDetail,
8
+ ForwardRuleItem,
9
+ ForwardRuleSaveRequest,
10
+ ForwardRuleSetting,
11
+ ForwardRuleTestRequest,
12
+ ForwardRuleTestResult,
13
+ PageQuery,
14
+ PageResult,
15
+ )
16
+ from .base import OpenAbstractApi
17
+
18
+
19
+ class ForwardRuleApi(OpenAbstractApi):
20
+ """消息规则(仅会员)。"""
21
+
22
+ def list(self, query: Optional[PageQuery] = None) -> PageResult[ForwardRuleItem]:
23
+ body = query if query is not None else PageQuery()
24
+ result = self.execute_open(
25
+ "POST", "/api/open/forwardRule/list", body, PageResult[ForwardRuleItem]
26
+ )
27
+ return result or PageResult(list=[])
28
+
29
+ def detail(self, rule_id: int) -> ForwardRuleDetail:
30
+ path = self.append_query("/api/open/forwardRule/detail", {"ruleId": int(rule_id)})
31
+ return self.execute_open("GET", path, None, ForwardRuleDetail)
32
+
33
+ def add(self, req: ForwardRuleSaveRequest) -> None:
34
+ self.execute_open("POST", "/api/open/forwardRule/add", req, None)
35
+
36
+ def edit(self, req: ForwardRuleSaveRequest) -> None:
37
+ """修改消息规则;会整体覆盖模板变量和发送目标。"""
38
+
39
+ self.execute_open("POST", "/api/open/forwardRule/edit", req, None)
40
+
41
+ def delete(self, rule_id: int) -> None:
42
+ path = self.append_query("/api/open/forwardRule/delete", {"ruleId": int(rule_id)})
43
+ self.execute_open("DELETE", path, None, None)
44
+
45
+ def change_status(self, rule_id: int, status: int) -> None:
46
+ """启用 / 停用消息规则:1 启用,0 停用。"""
47
+
48
+ path = self.append_query(
49
+ "/api/open/forwardRule/changeStatus",
50
+ {"ruleId": int(rule_id), "status": int(status)},
51
+ )
52
+ self.execute_open("GET", path, None, None)
53
+
54
+ def test(self, req: ForwardRuleTestRequest) -> ForwardRuleTestResult:
55
+ """用模拟请求测试规则,不会真正发送消息。"""
56
+
57
+ return self.execute_open("POST", "/api/open/forwardRule/test", req, ForwardRuleTestResult)
58
+
59
+ def get_setting(self) -> ForwardRuleSetting:
60
+ return self.execute_open("GET", "/api/open/forwardRule/setting", None, ForwardRuleSetting)
61
+
62
+ def save_setting(self, mode: int) -> None:
63
+ """设置总开关:0 关闭,1 开启且未命中仍推送,2 开启且未命中不推送。"""
64
+
65
+ path = self.append_query("/api/open/forwardRule/setting", {"mode": int(mode)})
66
+ self.execute_open("GET", path, None, None)
67
+
68
+
69
+ __all__ = ["ForwardRuleApi"]
@@ -24,6 +24,8 @@ from .api import (
24
24
  FormApi,
25
25
  DocApi,
26
26
  ExcelApi,
27
+ ForwardLogApi,
28
+ ForwardRuleApi,
27
29
  )
28
30
  from .config import PushPlusConfig
29
31
  from .exceptions import PushPlusError
@@ -84,6 +86,8 @@ class PushPlusClient:
84
86
  self.form = FormApi(config, self.http_requester, self.access_key_manager)
85
87
  self.doc = DocApi(config, self.http_requester, self.access_key_manager)
86
88
  self.excel = ExcelApi(config, self.http_requester, self.access_key_manager)
89
+ self.forward_rule = ForwardRuleApi(config, self.http_requester, self.access_key_manager)
90
+ self.forward_log = ForwardLogApi(config, self.http_requester, self.access_key_manager)
87
91
 
88
92
  @classmethod
89
93
  def of(cls, config: PushPlusConfig) -> "PushPlusClient":
@@ -62,7 +62,7 @@ class PushPlusConfig:
62
62
  可显式设置 ``2 * 86400`` 等更长值来减少无用试探。
63
63
  """
64
64
 
65
- user_agent: str = "perk-pushplus-python-sdk/1.2.1"
65
+ user_agent: str = "perk-pushplus-python-sdk/1.2.3"
66
66
  """HTTP User-Agent 头。"""
67
67
 
68
68
  extra_headers: dict = field(default_factory=dict)
@@ -257,6 +257,142 @@ class ShareLogin(_IntCodeEnum):
257
257
  return self.value
258
258
 
259
259
 
260
+ class ForwardMode(_IntCodeEnum):
261
+ """消息规则总开关。0-关闭,1-开启且未命中仍推送,2-开启且未命中不推送。"""
262
+
263
+ OFF = 0
264
+ ON_FALLBACK = 1
265
+ ON_STRICT = 2
266
+
267
+ @property
268
+ def code(self) -> int:
269
+ return self.value
270
+
271
+ @property
272
+ def description(self) -> str:
273
+ return _FORWARD_MODE_DESCRIPTIONS[self]
274
+
275
+
276
+ _FORWARD_MODE_DESCRIPTIONS = {
277
+ ForwardMode.OFF: "关闭(推送与原来一致)",
278
+ ForwardMode.ON_FALLBACK: "开启,未命中时仍按默认方式推送",
279
+ ForwardMode.ON_STRICT: "开启,未命中时不推送",
280
+ }
281
+
282
+
283
+ class ForwardSourceType(_IntCodeEnum):
284
+ """消息规则触发来源。0-全部,1-消息接口,2-邮件。"""
285
+
286
+ ALL = 0
287
+ API = 1
288
+ MAIL = 2
289
+
290
+ @property
291
+ def code(self) -> int:
292
+ return self.value
293
+
294
+ @property
295
+ def description(self) -> str:
296
+ return _FORWARD_SOURCE_TYPE_DESCRIPTIONS[self]
297
+
298
+
299
+ _FORWARD_SOURCE_TYPE_DESCRIPTIONS = {
300
+ ForwardSourceType.ALL: "全部",
301
+ ForwardSourceType.API: "消息接口",
302
+ ForwardSourceType.MAIL: "邮件",
303
+ }
304
+
305
+
306
+ class ForwardVarSourceType(_IntCodeEnum):
307
+ """模板变量来源。1-请求头,2-Query参数,3-请求体,4-URL路径,5-主题(邮件)。"""
308
+
309
+ HEADER = 1
310
+ QUERY = 2
311
+ BODY = 3
312
+ PATH = 4
313
+ SUBJECT = 5
314
+
315
+ @property
316
+ def code(self) -> int:
317
+ return self.value
318
+
319
+
320
+ class ForwardExtractType(_IntCodeEnum):
321
+ """模板变量提取方式。1-序列化数据,2-正则表达式,3-JSONPath,4-原始全文。"""
322
+
323
+ SERIALIZED = 1
324
+ REGEX = 2
325
+ JSON_PATH = 3
326
+ RAW = 4
327
+
328
+ @property
329
+ def code(self) -> int:
330
+ return self.value
331
+
332
+
333
+ class ForwardMatchResult(_IntCodeEnum):
334
+ """触发记录匹配结果。0-条件不满足,1-已转发,2-频率限制,3-不在触发时间段,4-执行异常。"""
335
+
336
+ NOT_MATCHED = 0
337
+ FORWARDED = 1
338
+ RATE_LIMITED = 2
339
+ OUT_OF_TIME = 3
340
+ ERROR = 4
341
+
342
+ @property
343
+ def code(self) -> int:
344
+ return self.value
345
+
346
+ @property
347
+ def description(self) -> str:
348
+ return _FORWARD_MATCH_RESULT_DESCRIPTIONS[self]
349
+
350
+
351
+ _FORWARD_MATCH_RESULT_DESCRIPTIONS = {
352
+ ForwardMatchResult.NOT_MATCHED: "条件不满足",
353
+ ForwardMatchResult.FORWARDED: "已转发",
354
+ ForwardMatchResult.RATE_LIMITED: "频率限制",
355
+ ForwardMatchResult.OUT_OF_TIME: "不在触发时间段",
356
+ ForwardMatchResult.ERROR: "执行异常",
357
+ }
358
+
359
+
360
+ class ForwardConditionOperator(_StrCodeEnum):
361
+ """图形化触发条件运算符。"""
362
+
363
+ EQ = "eq"
364
+ NE = "ne"
365
+ CONTAINS = "contains"
366
+ NOT_CONTAINS = "notContains"
367
+ STARTS_WITH = "startsWith"
368
+ ENDS_WITH = "endsWith"
369
+ REGEX = "regex"
370
+ GT = "gt"
371
+ GTE = "gte"
372
+ LT = "lt"
373
+ LTE = "lte"
374
+ IN = "in"
375
+ NOT_IN = "notIn"
376
+ EMPTY = "empty"
377
+ NOT_EMPTY = "notEmpty"
378
+
379
+ @property
380
+ def code(self) -> str:
381
+ return self.value
382
+
383
+
384
+ class ForwardMessageType(_StrCodeEnum):
385
+ """消息规则发送目标的消息类型。也支持写成 ``{{变量名}}``。"""
386
+
387
+ ONE = "one"
388
+ TOPIC = "topic"
389
+ FRIEND = "friend"
390
+
391
+ @property
392
+ def code(self) -> str:
393
+ return self.value
394
+
395
+
260
396
  __all__ = [
261
397
  "Channel",
262
398
  "Template",
@@ -267,4 +403,11 @@ __all__ = [
267
403
  "FormStatus",
268
404
  "SharePerm",
269
405
  "ShareLogin",
406
+ "ForwardMode",
407
+ "ForwardSourceType",
408
+ "ForwardVarSourceType",
409
+ "ForwardExtractType",
410
+ "ForwardMatchResult",
411
+ "ForwardConditionOperator",
412
+ "ForwardMessageType",
270
413
  ]
@@ -59,6 +59,21 @@ from .open_form import (
59
59
  FormTheme,
60
60
  )
61
61
  from .open_doc import DocContent, DocListItem, DocListQuery, DocVo, ExcelContent, ExcelVo
62
+ from .open_forward import (
63
+ ForwardCondition,
64
+ ForwardConditionItem,
65
+ ForwardLogDetail,
66
+ ForwardLogItem,
67
+ ForwardLogListQuery,
68
+ ForwardRuleDetail,
69
+ ForwardRuleItem,
70
+ ForwardRuleSaveRequest,
71
+ ForwardRuleSetting,
72
+ ForwardRuleTestRequest,
73
+ ForwardRuleTestResult,
74
+ ForwardTarget,
75
+ ForwardVariable,
76
+ )
62
77
 
63
78
  __all__ = [
64
79
  "ApiResponse",
@@ -136,4 +151,17 @@ __all__ = [
136
151
  "DocContent",
137
152
  "ExcelVo",
138
153
  "ExcelContent",
154
+ "ForwardConditionItem",
155
+ "ForwardCondition",
156
+ "ForwardVariable",
157
+ "ForwardTarget",
158
+ "ForwardRuleItem",
159
+ "ForwardRuleDetail",
160
+ "ForwardRuleSaveRequest",
161
+ "ForwardRuleTestRequest",
162
+ "ForwardRuleTestResult",
163
+ "ForwardRuleSetting",
164
+ "ForwardLogListQuery",
165
+ "ForwardLogItem",
166
+ "ForwardLogDetail",
139
167
  ]
@@ -0,0 +1,247 @@
1
+ """开放接口 - 消息规则与触发记录模型。"""
2
+ from __future__ import annotations
3
+
4
+ from dataclasses import dataclass
5
+ from typing import Any, Dict, List, Optional
6
+
7
+
8
+ @dataclass
9
+ class ForwardConditionItem:
10
+ """图形化触发条件中的单条比较。"""
11
+
12
+ varName: Optional[str] = None
13
+ operator: Optional[str] = None
14
+ value: Optional[str] = None
15
+
16
+
17
+ @dataclass
18
+ class ForwardCondition:
19
+ """图形化触发条件。"""
20
+
21
+ logic: Optional[str] = None
22
+ items: Optional[List[ForwardConditionItem]] = None
23
+
24
+
25
+ @dataclass
26
+ class ForwardVariable:
27
+ """模板变量。"""
28
+
29
+ id: Optional[int] = None
30
+ ruleId: Optional[int] = None
31
+ varName: Optional[str] = None
32
+ sourceType: Optional[int] = None
33
+ """1-请求头,2-Query参数,3-请求体,4-URL路径,5-主题(邮件)。"""
34
+ extractType: Optional[int] = None
35
+ """1-序列化数据,2-正则表达式,3-JSONPath,4-原始全文。"""
36
+ extractKey: Optional[str] = None
37
+ defaultValue: Optional[str] = None
38
+ sort: Optional[int] = None
39
+
40
+
41
+ @dataclass
42
+ class ForwardTarget:
43
+ """发送目标。"""
44
+
45
+ id: Optional[int] = None
46
+ ruleId: Optional[int] = None
47
+ channel: Optional[str] = None
48
+ option: Optional[str] = None
49
+ messageType: Optional[str] = None
50
+ topic: Optional[str] = None
51
+ to: Optional[str] = None
52
+ sort: Optional[int] = None
53
+
54
+
55
+ @dataclass
56
+ class ForwardRuleItem:
57
+ """消息规则列表项。"""
58
+
59
+ id: Optional[int] = None
60
+ tokenId: Optional[int] = None
61
+ tokenName: Optional[str] = None
62
+ ruleName: Optional[str] = None
63
+ sourceType: Optional[int] = None
64
+ sourceTypeName: Optional[str] = None
65
+ status: Optional[int] = None
66
+ sort: Optional[int] = None
67
+ conditionExpr: Optional[str] = None
68
+ targetCount: Optional[int] = None
69
+ createTime: Optional[str] = None
70
+
71
+
72
+ @dataclass
73
+ class ForwardRuleDetail:
74
+ """消息规则详情。"""
75
+
76
+ id: Optional[int] = None
77
+ tokenId: Optional[int] = None
78
+ ruleName: Optional[str] = None
79
+ sourceType: Optional[int] = None
80
+ status: Optional[int] = None
81
+ sort: Optional[int] = None
82
+ conditionExpr: Optional[str] = None
83
+ condition: Optional[ForwardCondition] = None
84
+ titleTemplate: Optional[str] = None
85
+ contentTemplate: Optional[str] = None
86
+ template: Optional[str] = None
87
+ pre: Optional[str] = None
88
+ stopOnMatch: Optional[int] = None
89
+ limitPeriod: Optional[int] = None
90
+ limitCount: Optional[int] = None
91
+ activeStartTime: Optional[str] = None
92
+ activeEndTime: Optional[str] = None
93
+ activeWeekdays: Optional[str] = None
94
+ remark: Optional[str] = None
95
+ variables: Optional[List[ForwardVariable]] = None
96
+ targets: Optional[List[ForwardTarget]] = None
97
+ createTime: Optional[str] = None
98
+
99
+
100
+ @dataclass
101
+ class ForwardRuleSaveRequest:
102
+ """新增 / 修改消息规则(修改时 ``id`` 必填)。"""
103
+
104
+ ruleName: Optional[str] = None
105
+ id: Optional[int] = None
106
+ tokenId: Optional[int] = None
107
+ sourceType: Optional[int] = None
108
+ status: Optional[int] = None
109
+ sort: Optional[int] = None
110
+ condition: Optional[ForwardCondition] = None
111
+ conditionExpr: Optional[str] = None
112
+ titleTemplate: Optional[str] = None
113
+ contentTemplate: Optional[str] = None
114
+ template: Optional[str] = None
115
+ pre: Optional[str] = None
116
+ stopOnMatch: Optional[int] = None
117
+ limitPeriod: Optional[int] = None
118
+ limitCount: Optional[int] = None
119
+ activeStartTime: Optional[str] = None
120
+ activeEndTime: Optional[str] = None
121
+ activeWeekdays: Optional[str] = None
122
+ remark: Optional[str] = None
123
+ variables: Optional[List[ForwardVariable]] = None
124
+ targets: Optional[List[ForwardTarget]] = None
125
+
126
+
127
+ @dataclass
128
+ class ForwardRuleTestRequest:
129
+ """测试消息规则请求。不会真正发送消息。"""
130
+
131
+ sourceType: Optional[int] = None
132
+ contentType: Optional[str] = None
133
+ headers: Optional[Dict[str, Any]] = None
134
+ query: Optional[Dict[str, Any]] = None
135
+ body: Optional[str] = None
136
+ title: Optional[str] = None
137
+ mailFrom: Optional[str] = None
138
+ mailTo: Optional[str] = None
139
+ mailCc: Optional[str] = None
140
+ condition: Optional[ForwardCondition] = None
141
+ conditionExpr: Optional[str] = None
142
+ titleTemplate: Optional[str] = None
143
+ contentTemplate: Optional[str] = None
144
+ template: Optional[str] = None
145
+ pre: Optional[str] = None
146
+ variables: Optional[List[ForwardVariable]] = None
147
+
148
+
149
+ @dataclass
150
+ class ForwardRuleTestResult:
151
+ """测试消息规则结果。"""
152
+
153
+ variables: Optional[Dict[str, Any]] = None
154
+ matched: Optional[bool] = None
155
+ conditionExpr: Optional[str] = None
156
+ errorMessage: Optional[str] = None
157
+ title: Optional[str] = None
158
+ content: Optional[str] = None
159
+ template: Optional[str] = None
160
+
161
+
162
+ @dataclass
163
+ class ForwardRuleSetting:
164
+ """消息规则总开关。"""
165
+
166
+ mode: Optional[int] = None
167
+ """0-关闭,1-开启且未命中仍推送,2-开启且未命中不推送。"""
168
+
169
+
170
+ @dataclass
171
+ class ForwardLogListQuery:
172
+ """触发记录分页查询。官方结构是 ``{current, pageSize, params:{ruleId, matchResult}}``。"""
173
+
174
+ current: Optional[int] = None
175
+ pageSize: Optional[int] = None
176
+ params: Optional[Dict[str, Any]] = None
177
+
178
+ @classmethod
179
+ def of(
180
+ cls,
181
+ current: Optional[int] = 1,
182
+ page_size: Optional[int] = 20,
183
+ rule_id: Optional[int] = None,
184
+ match_result: Optional[int] = None,
185
+ ) -> "ForwardLogListQuery":
186
+ params: Dict[str, Any] = {}
187
+ if rule_id is not None:
188
+ params["ruleId"] = rule_id
189
+ if match_result is not None:
190
+ params["matchResult"] = match_result
191
+ return cls(current=current, pageSize=page_size, params=params or None)
192
+
193
+
194
+ @dataclass
195
+ class ForwardLogItem:
196
+ """触发记录列表项。"""
197
+
198
+ id: Optional[int] = None
199
+ ruleId: Optional[int] = None
200
+ ruleName: Optional[str] = None
201
+ sourceType: Optional[int] = None
202
+ sourceTypeName: Optional[str] = None
203
+ requestIp: Optional[str] = None
204
+ matchResult: Optional[int] = None
205
+ matchResultName: Optional[str] = None
206
+ shortCodes: Optional[str] = None
207
+ errorMessage: Optional[str] = None
208
+ createTime: Optional[str] = None
209
+
210
+
211
+ @dataclass
212
+ class ForwardLogDetail:
213
+ """触发记录详情。"""
214
+
215
+ id: Optional[int] = None
216
+ ruleId: Optional[int] = None
217
+ ruleName: Optional[str] = None
218
+ sourceType: Optional[int] = None
219
+ sourceTypeName: Optional[str] = None
220
+ requestIp: Optional[str] = None
221
+ requestMethod: Optional[str] = None
222
+ requestHeaders: Optional[str] = None
223
+ requestQuery: Optional[str] = None
224
+ requestBody: Optional[str] = None
225
+ variables: Optional[str] = None
226
+ matchResult: Optional[int] = None
227
+ matchResultName: Optional[str] = None
228
+ shortCodes: Optional[str] = None
229
+ errorMessage: Optional[str] = None
230
+ createTime: Optional[str] = None
231
+
232
+
233
+ __all__ = [
234
+ "ForwardConditionItem",
235
+ "ForwardCondition",
236
+ "ForwardVariable",
237
+ "ForwardTarget",
238
+ "ForwardRuleItem",
239
+ "ForwardRuleDetail",
240
+ "ForwardRuleSaveRequest",
241
+ "ForwardRuleTestRequest",
242
+ "ForwardRuleTestResult",
243
+ "ForwardRuleSetting",
244
+ "ForwardLogListQuery",
245
+ "ForwardLogItem",
246
+ "ForwardLogDetail",
247
+ ]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: perk-pushplus-sdk
3
- Version: 1.2.2
3
+ Version: 1.2.3
4
4
  Summary: pushplus(推送加) 官方接口的 Python SDK,覆盖消息发送接口与全部开放接口。
5
5
  Author: perk-net
6
6
  License: Apache-2.0
@@ -35,7 +35,7 @@ Requires-Dist: responses>=0.23; extra == "dev"
35
35
  [pushplus(推送加)](https://www.pushplus.plus) 官方接口的 Python SDK,覆盖 **消息接口** 与 **全部开放接口**。
36
36
 
37
37
  - **消息接口**(`/send`、`/batchSend`):单渠道 + 多渠道发送,含 Builder API。
38
- - **开放接口**(`/api/open/...` 与 `/push/api/open/...`):用户、消息、消息 token、群组、群组用户、好友、webhook、渠道、ClawBot、QQ 机器人、功能设置、预处理信息、图片服务、push 表单、push 文档、push 表格。
38
+ - **开放接口**(`/api/open/...` 与 `/push/api/open/...`):用户、消息、消息 token、群组、群组用户、好友、webhook、渠道、ClawBot、QQ 机器人、功能设置、预处理信息、图片服务、push 表单、push 文档、push 表格、消息规则。
39
39
  - **AccessKey 自动管理**:缓存 + 过期前自动刷新;`code=401` 自动刷新并重试一次。
40
40
  - **本地限流守卫**:命中 `code=900` 后按 token 短路同 token 后续发送,避免被服务端长期封禁。
41
41
  - **回调解析**:`message_complate`、`add_topic_user`、`add_friend` 三类回调统一解析。
@@ -188,6 +188,19 @@ client.setting.change_is_send(1) # 启用发送
188
188
  # 预处理(会员)
189
189
  client.pre.test(...)
190
190
 
191
+ # 消息规则(会员)
192
+ from perk_pushplus import ForwardLogListQuery, ForwardRuleSaveRequest, ForwardVariable
193
+ client.forward_rule.save_setting(1) # 开启,未命中时仍按默认方式推送
194
+ client.forward_rule.add(ForwardRuleSaveRequest(
195
+ ruleName="阿里云监控多渠道",
196
+ tokenId=-1,
197
+ sourceType=1,
198
+ titleTemplate="{{alertName}}",
199
+ variables=[ForwardVariable(varName="alertName", sourceType=3, extractType=1, extractKey="alertName")],
200
+ ))
201
+ rules = client.forward_rule.list()
202
+ logs = client.forward_log.list(ForwardLogListQuery.of(1, 20, match_result=1))
203
+
191
204
  # 图片服务(一行上传到 PushPlus 图床)
192
205
  r = client.image.upload_file("/tmp/logo.png")
193
206
  print(r.url) # 可访问的图片地址
@@ -19,6 +19,8 @@ src/perk_pushplus/api/clawbot.py
19
19
  src/perk_pushplus/api/doc.py
20
20
  src/perk_pushplus/api/excel.py
21
21
  src/perk_pushplus/api/form.py
22
+ src/perk_pushplus/api/forward_log.py
23
+ src/perk_pushplus/api/forward_rule.py
22
24
  src/perk_pushplus/api/friend.py
23
25
  src/perk_pushplus/api/image.py
24
26
  src/perk_pushplus/api/message.py
@@ -39,6 +41,7 @@ src/perk_pushplus/models/open_channel.py
39
41
  src/perk_pushplus/models/open_clawbot.py
40
42
  src/perk_pushplus/models/open_doc.py
41
43
  src/perk_pushplus/models/open_form.py
44
+ src/perk_pushplus/models/open_forward.py
42
45
  src/perk_pushplus/models/open_friend.py
43
46
  src/perk_pushplus/models/open_image.py
44
47
  src/perk_pushplus/models/open_message.py
@@ -5,6 +5,9 @@ from perk_pushplus import (
5
5
  CallbackEvent,
6
6
  Channel,
7
7
  ErrorCode,
8
+ ForwardConditionOperator,
9
+ ForwardMatchResult,
10
+ ForwardMode,
8
11
  PushPlusError,
9
12
  SendStatus,
10
13
  Template,
@@ -49,6 +52,13 @@ def test_error_code_rate_limited():
49
52
  assert ErrorCode.from_code(None) is ErrorCode.UNKNOWN
50
53
 
51
54
 
55
+ def test_forward_mode_and_match_result():
56
+ assert ForwardMode.ON_FALLBACK.code == 1
57
+ assert ForwardMode.ON_STRICT.description == "开启,未命中时不推送"
58
+ assert ForwardMatchResult.FORWARDED.description == "已转发"
59
+ assert ForwardConditionOperator.NOT_CONTAINS.value == "notContains"
60
+
61
+
52
62
  def test_pushplus_error_exposes_metadata():
53
63
  exc = PushPlusError("rate", code=900)
54
64
  assert exc.code == 900
@@ -260,6 +260,70 @@ def test_friend_and_topic_user_blacklist():
260
260
  assert json.loads(topic_list[3])["params"]["topicId"] == 100
261
261
 
262
262
 
263
+ def test_forward_rule_and_log():
264
+ req = ScriptedRequester()
265
+ req.push(
266
+ "/api/open/forwardRule/list",
267
+ 200,
268
+ _ok({"pageNum": 1, "list": [{"id": 1, "ruleName": "阿里云监控多渠道", "sourceType": 1}]}),
269
+ )
270
+ req.push("/api/open/forwardRule/add", 200, _ok(None))
271
+ req.push(
272
+ "/api/open/forwardRule/test",
273
+ 200,
274
+ _ok({"matched": True, "title": "ECS-内存使用率", "conditionExpr": "alertState == 'ALERT'"}),
275
+ )
276
+ req.push("/api/open/forwardRule/setting?mode=1", 200, _ok(None))
277
+ req.push("/api/open/forwardRule/setting", 200, _ok({"mode": 1}))
278
+ req.push(
279
+ "/api/open/forwardLog/list",
280
+ 200,
281
+ _ok({"pageNum": 1, "list": [{"id": 9, "ruleId": 1, "matchResult": 1}]}),
282
+ )
283
+ req.push(
284
+ "/api/open/forwardLog/detail",
285
+ 200,
286
+ _ok({"id": 9, "ruleId": 1, "requestBody": '{"alertState":"ALERT"}'}),
287
+ )
288
+ client = _build_client(req)
289
+
290
+ from perk_pushplus import (
291
+ ForwardLogListQuery,
292
+ ForwardRuleSaveRequest,
293
+ ForwardRuleTestRequest,
294
+ ForwardVariable,
295
+ )
296
+
297
+ page = client.forward_rule.list()
298
+ assert page.list[0].ruleName == "阿里云监控多渠道"
299
+ client.forward_rule.add(
300
+ ForwardRuleSaveRequest(
301
+ ruleName="阿里云监控多渠道",
302
+ tokenId=-1,
303
+ sourceType=1,
304
+ variables=[ForwardVariable(varName="alertState", sourceType=3, extractType=1, extractKey="alertState")],
305
+ )
306
+ )
307
+ tested = client.forward_rule.test(
308
+ ForwardRuleTestRequest(sourceType=1, body='{"alertState":"ALERT"}', conditionExpr="alertState == 'ALERT'")
309
+ )
310
+ assert tested.matched is True
311
+ client.forward_rule.save_setting(1)
312
+ setting = client.forward_rule.get_setting()
313
+ assert setting.mode == 1
314
+ logs = client.forward_log.list(ForwardLogListQuery.of(1, 20, rule_id=1, match_result=1))
315
+ assert logs.list[0].id == 9
316
+ detail = client.forward_log.detail(9)
317
+ assert "ALERT" in detail.requestBody
318
+
319
+ add_call = next(c for c in req.calls if "/api/open/forwardRule/add" in c[1])
320
+ assert json.loads(add_call[3])["tokenId"] == -1
321
+ assert any("setting?mode=1" in c[1] for c in req.calls)
322
+ log_list = next(c for c in req.calls if "/api/open/forwardLog/list" in c[1])
323
+ assert json.loads(log_list[3])["params"]["matchResult"] == 1
324
+ assert any("logId=9" in c[1] for c in req.calls)
325
+
326
+
263
327
  def test_form_list_uses_current_and_params():
264
328
  req = ScriptedRequester()
265
329
  req.push("/push/api/open/form/list", 200, _ok({"pageNum": 1, "pageSize": 20, "total": 0, "list": []}))