perk-pushplus-sdk 1.2.1__tar.gz → 1.2.2__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 (64) hide show
  1. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/PKG-INFO +16 -2
  2. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/README.md +15 -1
  3. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/pyproject.toml +1 -1
  4. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/src/perk_pushplus/__init__.py +13 -1
  5. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/src/perk_pushplus/api/__init__.py +2 -0
  6. perk_pushplus_sdk-1.2.2/src/perk_pushplus/api/qqbot.py +89 -0
  7. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/src/perk_pushplus/client.py +2 -0
  8. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/src/perk_pushplus/enums.py +2 -0
  9. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/src/perk_pushplus/models/__init__.py +14 -0
  10. perk_pushplus_sdk-1.2.2/src/perk_pushplus/models/open_qqbot.py +107 -0
  11. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/src/perk_pushplus/models/open_user.py +1 -0
  12. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/src/perk_pushplus_sdk.egg-info/PKG-INFO +16 -2
  13. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/src/perk_pushplus_sdk.egg-info/SOURCES.txt +2 -0
  14. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/tests/test_open_api.py +54 -0
  15. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/setup.cfg +0 -0
  16. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/src/perk_pushplus/access_key.py +0 -0
  17. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/src/perk_pushplus/api/access_key.py +0 -0
  18. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/src/perk_pushplus/api/base.py +0 -0
  19. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/src/perk_pushplus/api/channel.py +0 -0
  20. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/src/perk_pushplus/api/clawbot.py +0 -0
  21. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/src/perk_pushplus/api/doc.py +0 -0
  22. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/src/perk_pushplus/api/excel.py +0 -0
  23. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/src/perk_pushplus/api/form.py +0 -0
  24. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/src/perk_pushplus/api/friend.py +0 -0
  25. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/src/perk_pushplus/api/image.py +0 -0
  26. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/src/perk_pushplus/api/message.py +0 -0
  27. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/src/perk_pushplus/api/message_token.py +0 -0
  28. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/src/perk_pushplus/api/open_message.py +0 -0
  29. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/src/perk_pushplus/api/pre.py +0 -0
  30. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/src/perk_pushplus/api/setting.py +0 -0
  31. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/src/perk_pushplus/api/topic.py +0 -0
  32. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/src/perk_pushplus/api/topic_user.py +0 -0
  33. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/src/perk_pushplus/api/user.py +0 -0
  34. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/src/perk_pushplus/api/webhook.py +0 -0
  35. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/src/perk_pushplus/callback_parser.py +0 -0
  36. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/src/perk_pushplus/config.py +0 -0
  37. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/src/perk_pushplus/exceptions.py +0 -0
  38. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/src/perk_pushplus/http.py +0 -0
  39. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/src/perk_pushplus/models/base.py +0 -0
  40. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/src/perk_pushplus/models/callback.py +0 -0
  41. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/src/perk_pushplus/models/open_access.py +0 -0
  42. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/src/perk_pushplus/models/open_channel.py +0 -0
  43. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/src/perk_pushplus/models/open_clawbot.py +0 -0
  44. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/src/perk_pushplus/models/open_doc.py +0 -0
  45. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/src/perk_pushplus/models/open_form.py +0 -0
  46. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/src/perk_pushplus/models/open_friend.py +0 -0
  47. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/src/perk_pushplus/models/open_image.py +0 -0
  48. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/src/perk_pushplus/models/open_message.py +0 -0
  49. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/src/perk_pushplus/models/open_pre.py +0 -0
  50. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/src/perk_pushplus/models/open_setting.py +0 -0
  51. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/src/perk_pushplus/models/open_token.py +0 -0
  52. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/src/perk_pushplus/models/open_topic.py +0 -0
  53. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/src/perk_pushplus/models/open_webhook.py +0 -0
  54. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/src/perk_pushplus/models/send.py +0 -0
  55. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/src/perk_pushplus/multipart.py +0 -0
  56. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/src/perk_pushplus/py.typed +0 -0
  57. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/src/perk_pushplus/rate_limit.py +0 -0
  58. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/src/perk_pushplus_sdk.egg-info/dependency_links.txt +0 -0
  59. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/src/perk_pushplus_sdk.egg-info/requires.txt +0 -0
  60. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/src/perk_pushplus_sdk.egg-info/top_level.txt +0 -0
  61. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/tests/test_enums_and_exceptions.py +0 -0
  62. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/tests/test_image_api.py +0 -0
  63. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/tests/test_message_api.py +0 -0
  64. {perk_pushplus_sdk-1.2.1 → perk_pushplus_sdk-1.2.2}/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.1
3
+ Version: 1.2.2
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、功能设置、预处理信息、图片服务、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` 三类回调统一解析。
@@ -168,6 +168,20 @@ topic_blacklist = client.topic_user.blacklist_list(TopicUserListQuery.of(1, 20,
168
168
  # webhook 渠道
169
169
  webhooks = client.webhook.list()
170
170
 
171
+ # QQ 机器人:绑定 -> 认领群 -> 建配置 -> 发到群
172
+ from perk_pushplus import QqBotSaveRequest
173
+ link = client.qq_bot.get_bind_link() # link.url 生成二维码,或私聊发送 link.bindCode
174
+ bind = client.qq_bot.bot_info() # bind.isBind == 1 表示已绑定
175
+ qq_groups = client.qq_bot.group_list()
176
+ client.qq_bot.add(QqBotSaveRequest(qqName="运维告警群", qqCode="ops-group", qqGroupId=qq_groups[0].id))
177
+ client.send(SendRequest(
178
+ title="服务告警",
179
+ content="订单服务响应超时",
180
+ channel=Channel.QQ,
181
+ option="ops-group", # 不传 option 则发给自己
182
+ template=Template.TXT,
183
+ ))
184
+
171
185
  # 设置
172
186
  client.setting.change_is_send(1) # 启用发送
173
187
 
@@ -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、功能设置、预处理信息、图片服务、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` 三类回调统一解析。
@@ -136,6 +136,20 @@ topic_blacklist = client.topic_user.blacklist_list(TopicUserListQuery.of(1, 20,
136
136
  # webhook 渠道
137
137
  webhooks = client.webhook.list()
138
138
 
139
+ # QQ 机器人:绑定 -> 认领群 -> 建配置 -> 发到群
140
+ from perk_pushplus import QqBotSaveRequest
141
+ link = client.qq_bot.get_bind_link() # link.url 生成二维码,或私聊发送 link.bindCode
142
+ bind = client.qq_bot.bot_info() # bind.isBind == 1 表示已绑定
143
+ qq_groups = client.qq_bot.group_list()
144
+ client.qq_bot.add(QqBotSaveRequest(qqName="运维告警群", qqCode="ops-group", qqGroupId=qq_groups[0].id))
145
+ client.send(SendRequest(
146
+ title="服务告警",
147
+ content="订单服务响应超时",
148
+ channel=Channel.QQ,
149
+ option="ops-group", # 不传 option 则发给自己
150
+ template=Template.TXT,
151
+ ))
152
+
139
153
  # 设置
140
154
  client.setting.change_is_send(1) # 启用发送
141
155
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "perk-pushplus-sdk"
7
- version = "1.2.1"
7
+ version = "1.2.2"
8
8
  description = "pushplus(推送加) 官方接口的 Python SDK,覆盖消息发送接口与全部开放接口。"
9
9
  readme = { file = "README.md", content-type = "text/markdown" }
10
10
  requires-python = ">=3.8"
@@ -84,6 +84,12 @@ from .models import (
84
84
  PreItem,
85
85
  PreSaveRequest,
86
86
  PreTestRequest,
87
+ QqBotBindInfo,
88
+ QqBotBindLink,
89
+ QqBotInfo,
90
+ QqBotItem,
91
+ QqBotSaveRequest,
92
+ QqGroupItem,
87
93
  SendCount,
88
94
  SendMessageResult,
89
95
  SendRequest,
@@ -108,7 +114,7 @@ from .models import (
108
114
  )
109
115
  from .rate_limit import RateLimitGuard
110
116
 
111
- __version__ = "1.2.1"
117
+ __version__ = "1.2.2"
112
118
 
113
119
  __all__ = [
114
120
  "__version__",
@@ -175,6 +181,12 @@ __all__ = [
175
181
  "ClawBotQrCode",
176
182
  "ClawBotInfo",
177
183
  "ClawBotMessage",
184
+ "QqBotBindLink",
185
+ "QqBotInfo",
186
+ "QqBotBindInfo",
187
+ "QqGroupItem",
188
+ "QqBotItem",
189
+ "QqBotSaveRequest",
178
190
  "UserDefaultItem",
179
191
  "UserDefaultDetail",
180
192
  "UserDefaultSaveRequest",
@@ -12,6 +12,7 @@ from .message import MessageApi
12
12
  from .message_token import MessageTokenApi
13
13
  from .open_message import OpenMessageApi
14
14
  from .pre import PreApi
15
+ from .qqbot import QqBotApi
15
16
  from .setting import SettingApi
16
17
  from .topic import TopicApi
17
18
  from .topic_user import TopicUserApi
@@ -32,6 +33,7 @@ __all__ = [
32
33
  "WebhookApi",
33
34
  "ChannelApi",
34
35
  "ClawBotApi",
36
+ "QqBotApi",
35
37
  "SettingApi",
36
38
  "PreApi",
37
39
  "ImageApi",
@@ -0,0 +1,89 @@
1
+ """开放接口 - QQ 机器人(文档「九. QQ机器人接口」)。"""
2
+ from __future__ import annotations
3
+
4
+ from dataclasses import replace
5
+ from typing import List, Optional
6
+
7
+ from ..models import (
8
+ PageQuery,
9
+ PageResult,
10
+ QqBotBindInfo,
11
+ QqBotBindLink,
12
+ QqBotItem,
13
+ QqBotSaveRequest,
14
+ QqGroupItem,
15
+ )
16
+ from .base import OpenAbstractApi
17
+
18
+ SEND_TYPE_QQ_GROUP = 2
19
+ """发送到 QQ 群,目前渠道配置仅支持该类型。"""
20
+
21
+
22
+ class QqBotApi(OpenAbstractApi):
23
+ """QQ 机器人绑定与渠道配置相关接口。"""
24
+
25
+ def get_bind_link(self, refresh: bool = False) -> QqBotBindLink:
26
+ """获取绑定链接与绑定码;``refresh=True`` 时旧绑定码失效并重新生成。"""
27
+
28
+ path = "/api/open/qqBot/getBindLink"
29
+ if refresh:
30
+ path = self.append_query(path, {"refresh": "true"})
31
+ return self.execute_open("GET", path, None, QqBotBindLink)
32
+
33
+ def bot_info(self) -> QqBotBindInfo:
34
+ """查询绑定状态。"""
35
+
36
+ return self.execute_open(
37
+ "GET", "/api/open/qqBot/botInfo", None, QqBotBindInfo
38
+ )
39
+
40
+ def unbind(self) -> None:
41
+ """解绑 QQ 机器人。"""
42
+
43
+ self.execute_open("GET", "/api/open/qqBot/unbind", None, None)
44
+
45
+ def group_list(self) -> List[QqGroupItem]:
46
+ """获取机器人已加入的 QQ 群列表。"""
47
+
48
+ result = self.execute_open(
49
+ "GET", "/api/open/qqBot/groupList", None, List[QqGroupItem]
50
+ )
51
+ return result or []
52
+
53
+ def list(self, query: Optional[PageQuery] = None) -> PageResult[QqBotItem]:
54
+ """获取 QQ 机器人渠道配置列表。"""
55
+
56
+ body = query if query is not None else PageQuery()
57
+ result = self.execute_open(
58
+ "POST", "/api/open/qqBot/list", body, PageResult[QqBotItem]
59
+ )
60
+ return result or PageResult(list=[])
61
+
62
+ def add(self, request: QqBotSaveRequest) -> None:
63
+ """新增渠道配置,用于把消息发送到指定 QQ 群;发给自己无需创建配置。"""
64
+
65
+ self.execute_open(
66
+ "POST", "/api/open/qqBot/add", _with_default_send_type(request), None
67
+ )
68
+
69
+ def edit(self, request: QqBotSaveRequest) -> None:
70
+ """修改渠道配置;配置编码不可修改。"""
71
+
72
+ self.execute_open(
73
+ "POST", "/api/open/qqBot/edit", _with_default_send_type(request), None
74
+ )
75
+
76
+ def delete(self, config_id: int) -> None:
77
+ """删除渠道配置。"""
78
+
79
+ path = self.append_query("/api/open/qqBot/delete", {"id": int(config_id)})
80
+ self.execute_open("DELETE", path, None, None)
81
+
82
+
83
+ def _with_default_send_type(request: QqBotSaveRequest) -> QqBotSaveRequest:
84
+ if request is None or request.sendType is not None:
85
+ return request
86
+ return replace(request, sendType=SEND_TYPE_QQ_GROUP)
87
+
88
+
89
+ __all__ = ["QqBotApi", "SEND_TYPE_QQ_GROUP"]
@@ -15,6 +15,7 @@ from .api import (
15
15
  MessageTokenApi,
16
16
  OpenMessageApi,
17
17
  PreApi,
18
+ QqBotApi,
18
19
  SettingApi,
19
20
  TopicApi,
20
21
  TopicUserApi,
@@ -76,6 +77,7 @@ class PushPlusClient:
76
77
  self.webhook = WebhookApi(config, self.http_requester, self.access_key_manager)
77
78
  self.channel = ChannelApi(config, self.http_requester, self.access_key_manager)
78
79
  self.claw_bot = ClawBotApi(config, self.http_requester, self.access_key_manager)
80
+ self.qq_bot = QqBotApi(config, self.http_requester, self.access_key_manager)
79
81
  self.setting = SettingApi(config, self.http_requester, self.access_key_manager)
80
82
  self.pre = PreApi(config, self.http_requester, self.access_key_manager)
81
83
  self.image = ImageApi(config, self.http_requester, self.access_key_manager)
@@ -42,6 +42,8 @@ class Channel(_StrCodeEnum):
42
42
  """App 渠道(安卓/鸿蒙/iOS)。"""
43
43
  CLAWBOT = "clawbot"
44
44
  """微信 ClawBot。"""
45
+ QQ = "qq"
46
+ """QQ 机器人;不带 option 发给自己,option 填配置编码则发到对应 QQ 群。"""
45
47
 
46
48
  @property
47
49
  def code(self) -> str:
@@ -36,6 +36,14 @@ from .open_friend import FriendBlacklistItem, FriendItem, FriendQrCode
36
36
  from .open_webhook import WebhookItem, WebhookSaveRequest
37
37
  from .open_channel import CpItem, MailDetail, MailItem, MpItem
38
38
  from .open_clawbot import ClawBotInfo, ClawBotMessage, ClawBotQrCode
39
+ from .open_qqbot import (
40
+ QqBotBindInfo,
41
+ QqBotBindLink,
42
+ QqBotInfo,
43
+ QqBotItem,
44
+ QqBotSaveRequest,
45
+ QqGroupItem,
46
+ )
39
47
  from .open_setting import UserDefaultDetail, UserDefaultItem, UserDefaultSaveRequest
40
48
  from .open_pre import PreDetail, PreItem, PreSaveRequest, PreTestRequest
41
49
  from .open_image import ImageItem, ImageUploadResult, ImageUploadToken
@@ -97,6 +105,12 @@ __all__ = [
97
105
  "ClawBotQrCode",
98
106
  "ClawBotInfo",
99
107
  "ClawBotMessage",
108
+ "QqBotBindLink",
109
+ "QqBotInfo",
110
+ "QqBotBindInfo",
111
+ "QqGroupItem",
112
+ "QqBotItem",
113
+ "QqBotSaveRequest",
100
114
  "UserDefaultItem",
101
115
  "UserDefaultDetail",
102
116
  "UserDefaultSaveRequest",
@@ -0,0 +1,107 @@
1
+ """开放接口 - QQ 机器人模型。"""
2
+ from __future__ import annotations
3
+
4
+ from dataclasses import dataclass
5
+ from typing import List, Optional
6
+
7
+
8
+ @dataclass
9
+ class QqBotBindLink:
10
+ """QQ 机器人绑定链接与绑定码。"""
11
+
12
+ url: Optional[str] = None
13
+ """带参分享链接,用于生成扫码二维码;已绑定用户再次获取时可能为空。"""
14
+ bindCode: Optional[str] = None
15
+ """绑定码。已是好友时扫码收不到加好友事件,需私聊发送该码;认领 QQ 群也用此码。"""
16
+ expireSeconds: Optional[int] = None
17
+ """有效期秒数,默认 300。"""
18
+ botAppId: Optional[str] = None
19
+ """为当前用户分配的官方机器人 appId。"""
20
+ botName: Optional[str] = None
21
+ botAvatar: Optional[str] = None
22
+
23
+
24
+ @dataclass
25
+ class QqBotInfo:
26
+ """QQ 机器人详情。"""
27
+
28
+ botId: Optional[str] = None
29
+ username: Optional[str] = None
30
+ avatar: Optional[str] = None
31
+ appId: Optional[str] = None
32
+ shareUrl: Optional[str] = None
33
+ """官方分享链接,可用于拉机器人进群。"""
34
+
35
+
36
+ @dataclass
37
+ class QqBotBindInfo:
38
+ """QQ 机器人绑定状态。"""
39
+
40
+ isBind: Optional[int] = None
41
+ """0-未绑定,1-已绑定。"""
42
+ receiveStatus: Optional[int] = None
43
+ """1-可接收,0-用户已关闭单聊接收。"""
44
+ createTime: Optional[str] = None
45
+ botInfo: Optional[QqBotInfo] = None
46
+
47
+
48
+ @dataclass
49
+ class QqGroupItem:
50
+ """机器人已加入的 QQ 群。"""
51
+
52
+ id: Optional[int] = None
53
+ """群编号;新增渠道配置时作为 ``qqGroupId`` 使用。"""
54
+ groupOpenId: Optional[str] = None
55
+ groupRemark: Optional[str] = None
56
+ status: Optional[int] = None
57
+ """1-在群,2-群消息接收关闭。"""
58
+ groupName: Optional[str] = None
59
+ """群名称,接口未授权时为空。"""
60
+ groupFingerMemo: Optional[str] = None
61
+ groupClassText: Optional[str] = None
62
+ groupTags: Optional[List[str]] = None
63
+ groupMemberNum: Optional[int] = None
64
+ createTime: Optional[str] = None
65
+
66
+
67
+ @dataclass
68
+ class QqBotItem:
69
+ """QQ 机器人渠道配置列表项。"""
70
+
71
+ id: Optional[int] = None
72
+ qqName: Optional[str] = None
73
+ qqCode: Optional[str] = None
74
+ """配置编码;发送消息时作为 ``option`` 传入。"""
75
+ sendType: Optional[int] = None
76
+ """2-发到 QQ 群。"""
77
+ qqGroupId: Optional[int] = None
78
+ groupRemark: Optional[str] = None
79
+ groupOpenId: Optional[str] = None
80
+ groupName: Optional[str] = None
81
+ updateTime: Optional[str] = None
82
+
83
+
84
+ @dataclass
85
+ class QqBotSaveRequest:
86
+ """新增/修改 QQ 机器人渠道配置请求。"""
87
+
88
+ id: Optional[int] = None
89
+ """修改时必填。"""
90
+ qqName: Optional[str] = None
91
+ """配置名称,必填,最多 64 个字符。"""
92
+ qqCode: Optional[str] = None
93
+ """配置编码,新增必填;仅支持字母、数字、下划线和中划线,创建后不可修改。"""
94
+ sendType: Optional[int] = None
95
+ """发送类型;留空时 SDK 自动填 2(发到 QQ 群)。"""
96
+ qqGroupId: Optional[int] = None
97
+ """QQ 群编号,必填,取自 ``group_list`` 返回的 ``id``。"""
98
+
99
+
100
+ __all__ = [
101
+ "QqBotBindLink",
102
+ "QqBotInfo",
103
+ "QqBotBindInfo",
104
+ "QqGroupItem",
105
+ "QqBotItem",
106
+ "QqBotSaveRequest",
107
+ ]
@@ -53,6 +53,7 @@ class SendCount:
53
53
  cpSendCount: Optional[int] = None
54
54
  webhookSendCount: Optional[int] = None
55
55
  mailSendCount: Optional[int] = None
56
+ qqBotSendCount: Optional[int] = None
56
57
 
57
58
 
58
59
  __all__ = ["VipInfo", "UserInfo", "UserLimitTime", "SendCount"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: perk-pushplus-sdk
3
- Version: 1.2.1
3
+ Version: 1.2.2
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、功能设置、预处理信息、图片服务、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` 三类回调统一解析。
@@ -168,6 +168,20 @@ topic_blacklist = client.topic_user.blacklist_list(TopicUserListQuery.of(1, 20,
168
168
  # webhook 渠道
169
169
  webhooks = client.webhook.list()
170
170
 
171
+ # QQ 机器人:绑定 -> 认领群 -> 建配置 -> 发到群
172
+ from perk_pushplus import QqBotSaveRequest
173
+ link = client.qq_bot.get_bind_link() # link.url 生成二维码,或私聊发送 link.bindCode
174
+ bind = client.qq_bot.bot_info() # bind.isBind == 1 表示已绑定
175
+ qq_groups = client.qq_bot.group_list()
176
+ client.qq_bot.add(QqBotSaveRequest(qqName="运维告警群", qqCode="ops-group", qqGroupId=qq_groups[0].id))
177
+ client.send(SendRequest(
178
+ title="服务告警",
179
+ content="订单服务响应超时",
180
+ channel=Channel.QQ,
181
+ option="ops-group", # 不传 option 则发给自己
182
+ template=Template.TXT,
183
+ ))
184
+
171
185
  # 设置
172
186
  client.setting.change_is_send(1) # 启用发送
173
187
 
@@ -25,6 +25,7 @@ src/perk_pushplus/api/message.py
25
25
  src/perk_pushplus/api/message_token.py
26
26
  src/perk_pushplus/api/open_message.py
27
27
  src/perk_pushplus/api/pre.py
28
+ src/perk_pushplus/api/qqbot.py
28
29
  src/perk_pushplus/api/setting.py
29
30
  src/perk_pushplus/api/topic.py
30
31
  src/perk_pushplus/api/topic_user.py
@@ -42,6 +43,7 @@ src/perk_pushplus/models/open_friend.py
42
43
  src/perk_pushplus/models/open_image.py
43
44
  src/perk_pushplus/models/open_message.py
44
45
  src/perk_pushplus/models/open_pre.py
46
+ src/perk_pushplus/models/open_qqbot.py
45
47
  src/perk_pushplus/models/open_setting.py
46
48
  src/perk_pushplus/models/open_token.py
47
49
  src/perk_pushplus/models/open_topic.py
@@ -292,3 +292,57 @@ def test_excel_import():
292
292
 
293
293
  imported = client.excel.import_excel(b"xlsx", "销售日报.xlsx")
294
294
  assert imported.docCode == "Sh3xY7kP"
295
+
296
+
297
+ def test_qq_bot_bind_and_group_config():
298
+ req = ScriptedRequester()
299
+ req.push(
300
+ "/api/open/qqBot/getBindLink",
301
+ 200,
302
+ _ok({"url": "https://qun.qq.com/qunpro/robot/share?robot_appid=1", "bindCode": "A1B2C3", "expireSeconds": 300}),
303
+ )
304
+ req.push(
305
+ "/api/open/qqBot/botInfo",
306
+ 200,
307
+ _ok({"isBind": 1, "receiveStatus": 1, "botInfo": {"appId": "1", "username": "pushplus"}}),
308
+ )
309
+ req.push(
310
+ "/api/open/qqBot/groupList",
311
+ 200,
312
+ _ok([{"id": 9, "groupOpenId": "OPEN-1", "status": 1, "groupName": "运维告警群", "groupTags": ["运维"]}]),
313
+ )
314
+ req.push("/api/open/qqBot/add", 200, _ok(None))
315
+ req.push(
316
+ "/api/open/qqBot/list",
317
+ 200,
318
+ _ok({"pageNum": 1, "pageSize": 20, "total": 1, "pages": 1, "list": [{"id": 3, "qqCode": "ops-group", "sendType": 2, "qqGroupId": 9}]}),
319
+ )
320
+ req.push("/api/open/qqBot/delete", 200, _ok(None))
321
+ client = _build_client(req)
322
+
323
+ from perk_pushplus import QqBotSaveRequest
324
+
325
+ link = client.qq_bot.get_bind_link(refresh=True)
326
+ assert link.bindCode == "A1B2C3"
327
+ assert "refresh=true" in next(c for c in req.calls if "getBindLink" in c[1])[1]
328
+
329
+ bind = client.qq_bot.bot_info()
330
+ assert bind.isBind == 1
331
+ assert bind.botInfo is not None and bind.botInfo.username == "pushplus"
332
+
333
+ groups = client.qq_bot.group_list()
334
+ assert groups[0].id == 9
335
+ assert groups[0].groupTags == ["运维"]
336
+
337
+ client.qq_bot.add(QqBotSaveRequest(qqName="运维告警群", qqCode="ops-group", qqGroupId=9))
338
+ add_call = next(c for c in req.calls if "/api/open/qqBot/add" in c[1])
339
+ assert add_call[2]["access-key"] == "ak-1"
340
+ assert json.loads(add_call[3])["sendType"] == 2
341
+
342
+ page = client.qq_bot.list()
343
+ assert page.list[0].qqCode == "ops-group"
344
+
345
+ client.qq_bot.delete(3)
346
+ delete_call = next(c for c in req.calls if "/api/open/qqBot/delete" in c[1])
347
+ assert delete_call[0] == "DELETE"
348
+ assert "id=3" in delete_call[1]