satori-python-adapter-qq 0.3.1__tar.gz → 0.3.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 (19) hide show
  1. {satori_python_adapter_qq-0.3.1 → satori_python_adapter_qq-0.3.3}/.mina/adapter_qq.toml +2 -2
  2. {satori_python_adapter_qq-0.3.1 → satori_python_adapter_qq-0.3.3}/PKG-INFO +2 -2
  3. {satori_python_adapter_qq-0.3.1 → satori_python_adapter_qq-0.3.3}/pyproject.toml +13 -15
  4. {satori_python_adapter_qq-0.3.1 → satori_python_adapter_qq-0.3.3}/src/satori/adapters/qq/api.py +26 -5
  5. {satori_python_adapter_qq-0.3.1 → satori_python_adapter_qq-0.3.3}/src/satori/adapters/qq/events/group.py +7 -3
  6. {satori_python_adapter_qq-0.3.1 → satori_python_adapter_qq-0.3.3}/src/satori/adapters/qq/main.py +9 -2
  7. {satori_python_adapter_qq-0.3.1 → satori_python_adapter_qq-0.3.3}/src/satori/adapters/qq/message.py +12 -1
  8. {satori_python_adapter_qq-0.3.1 → satori_python_adapter_qq-0.3.3}/src/satori/adapters/qq/utils.py +3 -0
  9. {satori_python_adapter_qq-0.3.1 → satori_python_adapter_qq-0.3.3}/src/satori/adapters/qq/websocket.py +9 -2
  10. {satori_python_adapter_qq-0.3.1 → satori_python_adapter_qq-0.3.3}/LICENSE +0 -0
  11. {satori_python_adapter_qq-0.3.1 → satori_python_adapter_qq-0.3.3}/README.md +0 -0
  12. {satori_python_adapter_qq-0.3.1 → satori_python_adapter_qq-0.3.3}/src/satori/adapters/qq/__init__.py +0 -0
  13. {satori_python_adapter_qq-0.3.1 → satori_python_adapter_qq-0.3.3}/src/satori/adapters/qq/audit_store.py +0 -0
  14. {satori_python_adapter_qq-0.3.1 → satori_python_adapter_qq-0.3.3}/src/satori/adapters/qq/events/__init__.py +0 -0
  15. {satori_python_adapter_qq-0.3.1 → satori_python_adapter_qq-0.3.3}/src/satori/adapters/qq/events/base.py +0 -0
  16. {satori_python_adapter_qq-0.3.1 → satori_python_adapter_qq-0.3.3}/src/satori/adapters/qq/events/guild.py +0 -0
  17. {satori_python_adapter_qq-0.3.1 → satori_python_adapter_qq-0.3.3}/src/satori/adapters/qq/events/interaction.py +0 -0
  18. {satori_python_adapter_qq-0.3.1 → satori_python_adapter_qq-0.3.3}/src/satori/adapters/qq/events/message.py +0 -0
  19. {satori_python_adapter_qq-0.3.1 → satori_python_adapter_qq-0.3.3}/src/satori/adapters/qq/exception.py +0 -0
@@ -1,12 +1,12 @@
1
1
  includes = ["src/satori/adapters/qq"]
2
2
  raw-dependencies = [
3
- "satori-python<1.4.0,>= 1.3.0",
3
+ "satori-python<1.4.0,>= 1.3.3",
4
4
  "cryptography>=46.0.4",
5
5
  ]
6
6
 
7
7
  [project]
8
8
  name = "satori-python-adapter-qq"
9
- version = "0.3.1"
9
+ version = "0.3.3"
10
10
  authors = [
11
11
  {name = "RF-Tar-Railt", email = "rf_tar_railt@qq.com"}
12
12
  ]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: satori-python-adapter-qq
3
- Version: 0.3.1
3
+ Version: 0.3.3
4
4
  Summary: Satori Protocol SDK for python, adapter for QQ
5
5
  Home-page: https://github.com/RF-Tar-Railt/satori-python
6
6
  Author-Email: RF-Tar-Railt <rf_tar_railt@qq.com>
@@ -17,7 +17,7 @@ Classifier: Operating System :: OS Independent
17
17
  Project-URL: Homepage, https://github.com/RF-Tar-Railt/satori-python
18
18
  Project-URL: Repository, https://github.com/RF-Tar-Railt/satori-python
19
19
  Requires-Python: <4.0,>=3.10
20
- Requires-Dist: satori-python<1.4.0,>=1.3.0
20
+ Requires-Dist: satori-python<1.4.0,>=1.3.3
21
21
  Requires-Dist: cryptography>=46.0.4
22
22
  Description-Content-Type: text/markdown
23
23
 
@@ -1,11 +1,11 @@
1
1
  [project]
2
2
  name = "satori-python-adapter-qq"
3
- version = "0.3.1"
3
+ version = "0.3.3"
4
4
  authors = [
5
5
  { name = "RF-Tar-Railt", email = "rf_tar_railt@qq.com" },
6
6
  ]
7
7
  dependencies = [
8
- "satori-python<1.4.0,>= 1.3.0",
8
+ "satori-python<1.4.0,>= 1.3.3",
9
9
  "cryptography>=46.0.4",
10
10
  ]
11
11
  description = "Satori Protocol SDK for python, adapter for QQ"
@@ -39,15 +39,14 @@ build-backend = "mina.backend"
39
39
 
40
40
  [dependency-groups]
41
41
  dev = [
42
- "isort>=5.13.2",
43
- "black>=24.4.0",
44
- "ruff>=0.4.1",
42
+ "black>=26.3.0",
43
+ "ruff>=0.15.1",
45
44
  "pre-commit>=3.7.0",
46
- "fix-future-annotations>=0.5.0",
47
45
  "mina-build<0.6,>=0.5.1",
48
46
  "pdm-mina>=0.3.2",
49
47
  "nonechat<0.7.0,>=0.6.0",
50
48
  "uvicorn[standard]>=0.37.0",
49
+ "pydantic>=2.13.1",
51
50
  ]
52
51
 
53
52
  [tool.pdm.build]
@@ -61,7 +60,7 @@ excludes = [
61
60
 
62
61
  [tool.pdm.scripts.format]
63
62
  composite = [
64
- "isort ./src/ ./example/",
63
+ "ruff check --select I --fix ./src/ ./example/",
65
64
  "black ./src/ ./example/",
66
65
  "ruff check",
67
66
  ]
@@ -75,14 +74,6 @@ line-length = 120
75
74
  include = "\\.pyi?$"
76
75
  extend-exclude = ""
77
76
 
78
- [tool.isort]
79
- profile = "black"
80
- line_length = 120
81
- skip_gitignore = true
82
- extra_standard_library = [
83
- "typing_extensions",
84
- ]
85
-
86
77
  [tool.ruff]
87
78
  line-length = 120
88
79
  target-version = "py310"
@@ -92,6 +83,7 @@ exclude = [
92
83
  "exam2.py",
93
84
  "src/satori/_vendor/*",
94
85
  ]
86
+ respect-gitignore = true
95
87
 
96
88
  [tool.ruff.lint]
97
89
  select = [
@@ -111,6 +103,12 @@ ignore = [
111
103
  "T201",
112
104
  ]
113
105
 
106
+ [tool.ruff.lint.isort]
107
+ extra-standard-library = [
108
+ "typing_extensions",
109
+ ]
110
+ force-sort-within-sections = false
111
+
114
112
  [tool.pyright]
115
113
  pythonPlatform = "All"
116
114
  pythonVersion = "3.10"
@@ -29,7 +29,7 @@ from satori.server.route import (
29
29
  )
30
30
 
31
31
  from .message import QQGroupMessageEncoder, QQGuildMessageEncoder, decode_segments
32
- from .utils import ROLE_MAPPING, QQBotNetwork, decode_channel, decode_guild, decode_member, decode_user
32
+ from .utils import ROLE_MAPPING, USER_AVATAR_URL, QQBotNetwork, decode_channel, decode_guild, decode_member, decode_user
33
33
 
34
34
 
35
35
  def apply(
@@ -141,7 +141,14 @@ def apply(
141
141
  )
142
142
  return decode_user(res)
143
143
  raise NotFoundException("qqguild platform does not support user.get without guild_id")
144
- raise NotFoundException("qq platform does not support user.get")
144
+ # raise NotFoundException("qq platform does not support user.get")
145
+ app_id = net.bot_id_mapping[login_getter(request.self_id, request.platform == "qqguild").id]
146
+ return decode_user(
147
+ {
148
+ "id": request.params["user_id"],
149
+ "avatar": USER_AVATAR_URL.format(app_id=app_id, user_id=request.params["user_id"]),
150
+ }
151
+ )
145
152
 
146
153
  @adapter.route(Api.GUILD_GET)
147
154
  async def guild_get(request: Request[GuildGetParam]):
@@ -152,7 +159,8 @@ def apply(
152
159
  f"guilds/{request.params['guild_id']}",
153
160
  )
154
161
  return decode_guild(res)
155
- raise NotFoundException("qq platform does not support guild.get")
162
+ # raise NotFoundException("qq platform does not support guild.get")
163
+ return Guild(request.params["guild_id"]) # type: ignore
156
164
 
157
165
  @adapter.route(Api.GUILD_LIST)
158
166
  async def guild_list(request: Request[GuildListParam]):
@@ -177,7 +185,9 @@ def apply(
177
185
  f"channels/{channel_id}",
178
186
  )
179
187
  return decode_channel(res)
180
- raise NotFoundException("qq platform does not support channel.get")
188
+ # raise NotFoundException("qq platform does not support channel.get")
189
+ is_private = request.params["channel_id"].startswith("private:")
190
+ return Channel(request.params["channel_id"], ChannelType.DIRECT if is_private else ChannelType.TEXT) # type: ignore
181
191
 
182
192
  @adapter.route(Api.CHANNEL_LIST)
183
193
  async def channel_list(request: Request[ChannelListParam]):
@@ -253,7 +263,18 @@ def apply(
253
263
  f"guilds/{guild_id}/members/{request.params['user_id']}",
254
264
  )
255
265
  return decode_member(res)
256
- raise NotFoundException("qq platform does not support guild.member.get")
266
+ # raise NotFoundException("qq platform does not support guild.member.get")
267
+ app_id = net.bot_id_mapping[login_getter(request.self_id, request.platform == "qqguild").id]
268
+ return Member(
269
+ decode_user(
270
+ {
271
+ "id": request.params["user_id"],
272
+ "avatar": USER_AVATAR_URL.format(app_id=app_id, user_id=request.params["user_id"]),
273
+ }
274
+ ),
275
+ joined_at=None,
276
+ roles=[ROLE_MAPPING["1"]],
277
+ )
257
278
 
258
279
  @adapter.route(Api.GUILD_MEMBER_LIST)
259
280
  async def guild_list_member(request: Request[GuildXXXListParam]):
@@ -5,7 +5,7 @@ from datetime import datetime
5
5
  from satori import EventType
6
6
  from satori.model import Channel, ChannelType, Event, Guild, User
7
7
 
8
- from ..utils import Payload
8
+ from ..utils import USER_AVATAR_URL, Payload
9
9
  from .base import register_event
10
10
 
11
11
 
@@ -17,7 +17,8 @@ async def friend_event(login, guild_login, net, payload: Payload):
17
17
  "FRIEND_ADD": EventType.FRIEND_ADDED,
18
18
  "FRIEND_DEL": EventType.FRIEND_REMOVED,
19
19
  }[payload.type or ""]
20
- user = User(raw["openid"])
20
+ app_id = net.bot_id_mapping[login.id]
21
+ user = User(raw["openid"], avatar=USER_AVATAR_URL.format(app_id=app_id, user_id=raw["openid"]))
21
22
  return Event(
22
23
  t,
23
24
  (
@@ -40,7 +41,10 @@ async def group_event(login, guild_login, net, payload: Payload):
40
41
  guild = Guild(raw["group_openid"])
41
42
  else:
42
43
  guild = Guild(raw["guild_id"])
43
- operator = User(raw["op_member_openid"])
44
+ app_id = net.bot_id_mapping[login.id]
45
+ operator = User(
46
+ raw["op_member_openid"], avatar=USER_AVATAR_URL.format(app_id=app_id, user_id=raw["op_member_openid"])
47
+ )
44
48
  t = {
45
49
  "GROUP_ADD_ROBOT": EventType.GUILD_ADDED,
46
50
  "GROUP_DEL_ROBOT": EventType.GUILD_REMOVED,
@@ -318,7 +318,9 @@ class QQBotWebhookAdapter(BaseAdapter):
318
318
  bot_info = await network.call_api("get", "users/@me")
319
319
  user = decode_user(bot_info)
320
320
  user.is_bot = True
321
- login = Login(0, LoginStatus.ONLINE, "qqbot", platform="qq", user=user, features=QQ_FEATURES.copy())
321
+ login = Login(
322
+ sn=0, status=LoginStatus.ONLINE, adapter="qqbot", platform="qq", user=user, features=QQ_FEATURES.copy()
323
+ )
322
324
  previous = next((lg for lg in self.logins if lg.id == login.id and lg.platform == "qq"), None)
323
325
  if previous:
324
326
  previous.user = login.user
@@ -331,7 +333,12 @@ class QQBotWebhookAdapter(BaseAdapter):
331
333
  event_type = EventType.LOGIN_ADDED
332
334
  await self.server.post(Event(event_type, datetime.now(), login))
333
335
  guild_login = Login(
334
- 0, LoginStatus.ONLINE, "qqbot", platform="qqguild", user=user, features=QQ_GUILD_FEATURES.copy()
336
+ sn=0,
337
+ status=LoginStatus.ONLINE,
338
+ adapter="qqbot",
339
+ platform="qqguild",
340
+ user=user,
341
+ features=QQ_GUILD_FEATURES.copy(),
335
342
  )
336
343
  previous = next((lg for lg in self.logins if lg.id == guild_login.id and lg.platform == "qqguild"), None)
337
344
  if previous:
@@ -21,6 +21,17 @@ from .utils import QQBotNetwork, parse_file_uri
21
21
 
22
22
  _BASE64_RE = re.compile(r"^data:([\w/.+-]+);base64,")
23
23
  MAX_FILESIZE_ONCE = 10 * 1024 * 1024 # 10MB
24
+ BUTTON_STYLES = {
25
+ "grey": 0,
26
+ "secondary": 0,
27
+ "blue": 1,
28
+ "primary": 1,
29
+ "success": 1,
30
+ "info": 2,
31
+ "warning": 3,
32
+ "danger": 3,
33
+ "link": 4,
34
+ }
24
35
 
25
36
 
26
37
  def escape(s: str) -> str:
@@ -530,7 +541,7 @@ class QQGroupMessageEncoder(QQBotMessageEncoder):
530
541
  "render_data": {
531
542
  "label": label,
532
543
  "visited_label": label,
533
- "style": 1 if attrs.get("class") == "primary" else 0,
544
+ "style": BUTTON_STYLES.get(attrs.get("class", "grey"), 1),
534
545
  },
535
546
  "action": {
536
547
  "type": {"input": 2, "link": 0}.get(attrs.get("type", "action"), 1),
@@ -18,6 +18,9 @@ CallMethod = Literal["get", "post", "fetch", "update", "multipart", "put", "dele
18
18
  class QQBotNetwork(Protocol):
19
19
  session: ClientSession
20
20
 
21
+ @property
22
+ def bot_id_mapping(self) -> dict[str, str]: ...
23
+
21
24
  async def call_api(self, method: CallMethod, action: str, params: dict | None = None) -> dict: ...
22
25
 
23
26
 
@@ -330,7 +330,9 @@ class QQBotWebsocketAdapter(BaseAdapter):
330
330
  async def refresh_login(self, profile: dict):
331
331
  user = decode_user(profile)
332
332
  user.is_bot = True
333
- login = Login(0, LoginStatus.ONLINE, "qqbot", platform="qq", user=user, features=QQ_FEATURES.copy())
333
+ login = Login(
334
+ sn=0, status=LoginStatus.ONLINE, adapter="qqbot", platform="qq", user=user, features=QQ_FEATURES.copy()
335
+ )
334
336
  previous = next((lg for lg in self.logins if lg.id == login.id and lg.platform == "qq"), None)
335
337
  if previous:
336
338
  previous.user = login.user
@@ -343,7 +345,12 @@ class QQBotWebsocketAdapter(BaseAdapter):
343
345
  event_type = EventType.LOGIN_ADDED
344
346
  await self.server.post(Event(event_type, datetime.now(), login))
345
347
  guild_login = Login(
346
- 0, LoginStatus.ONLINE, "qqbot", platform="qqguild", user=user, features=QQ_GUILD_FEATURES.copy()
348
+ sn=0,
349
+ status=LoginStatus.ONLINE,
350
+ adapter="qqbot",
351
+ platform="qqguild",
352
+ user=user,
353
+ features=QQ_GUILD_FEATURES.copy(),
347
354
  )
348
355
  previous = next((lg for lg in self.logins if lg.id == guild_login.id and lg.platform == "qqguild"), None)
349
356
  if previous: