mirror of
https://github.com/AstrBotDevs/AstrBot
synced 2026-07-15 17:30:13 +08:00
fix: align aiocqhttp poke payload with onebot v11 (#5773)
Co-authored-by: whatevertogo <whatevertogo@users.noreply.github.com>
This commit is contained in:
@@ -539,13 +539,36 @@ class Reply(BaseMessageComponent):
|
||||
|
||||
|
||||
class Poke(BaseMessageComponent):
|
||||
type: str = ComponentType.Poke
|
||||
id: int | None = 0
|
||||
qq: int | None = 0
|
||||
type: ComponentType = ComponentType.Poke
|
||||
_type: str | int = "126"
|
||||
id: int | str | None = 0
|
||||
qq: int | str | None = 0 # deprecated: legacy field, kept for compatibility
|
||||
|
||||
def __init__(self, type: str, **_) -> None:
|
||||
type = f"Poke:{type}"
|
||||
super().__init__(type=type, **_)
|
||||
def __init__(self, poke_type: str | int | None = None, **_) -> None:
|
||||
# Backward compatible with old signature: Poke(type="poke", ...)
|
||||
legacy_type = _.pop("type", None)
|
||||
if poke_type is None:
|
||||
poke_type = legacy_type
|
||||
if poke_type in (None, "", "poke", "Poke"):
|
||||
poke_type = "126"
|
||||
super().__init__(_type=str(poke_type), **_)
|
||||
|
||||
def target_id(self) -> str | None:
|
||||
"""Return normalized target id, compatible with old `qq` field."""
|
||||
for value in (self.id, self.qq):
|
||||
if value is None:
|
||||
continue
|
||||
text = str(value).strip()
|
||||
if text and text != "0":
|
||||
return text
|
||||
return None
|
||||
|
||||
def toDict(self):
|
||||
target_id = self.target_id()
|
||||
data = {"type": str(self._type or "126")}
|
||||
if target_id:
|
||||
data["id"] = target_id
|
||||
return {"type": "poke", "data": data}
|
||||
|
||||
|
||||
class Forward(BaseMessageComponent):
|
||||
|
||||
@@ -28,7 +28,7 @@ class RespondStage(Stage):
|
||||
Comp.At: lambda comp: bool(comp.qq) or bool(comp.name), # @
|
||||
Comp.Image: lambda comp: bool(comp.file), # 图片
|
||||
Comp.Reply: lambda comp: bool(comp.id) and comp.sender_id is not None, # 回复
|
||||
Comp.Poke: lambda comp: comp.id != 0 and comp.qq != 0, # 戳一戳
|
||||
Comp.Poke: lambda comp: comp.target_id() is not None, # 戳一戳
|
||||
Comp.Node: lambda comp: bool(comp.content), # 转发节点
|
||||
Comp.Nodes: lambda comp: bool(comp.nodes), # 多个转发节点
|
||||
Comp.File: lambda comp: bool(comp.file_ or comp.url),
|
||||
|
||||
@@ -191,7 +191,7 @@ class AiocqhttpAdapter(Platform):
|
||||
|
||||
if "sub_type" in event:
|
||||
if event["sub_type"] == "poke" and "target_id" in event:
|
||||
abm.message.append(Poke(qq=str(event["target_id"]), type="poke"))
|
||||
abm.message.append(Poke(id=str(event["target_id"])))
|
||||
|
||||
return abm
|
||||
|
||||
|
||||
59
tests/unit/test_aiocqhttp_poke.py
Normal file
59
tests/unit/test_aiocqhttp_poke.py
Normal file
@@ -0,0 +1,59 @@
|
||||
from unittest.mock import AsyncMock
|
||||
|
||||
import pytest
|
||||
|
||||
import astrbot.core.message.components as Comp
|
||||
from astrbot.core.message.message_event_result import MessageChain
|
||||
from astrbot.core.pipeline.respond.stage import RespondStage
|
||||
from astrbot.core.platform.sources.aiocqhttp.aiocqhttp_message_event import (
|
||||
AiocqhttpMessageEvent,
|
||||
)
|
||||
|
||||
|
||||
def test_poke_to_dict_matches_onebot_v11_segment_format():
|
||||
poke = Comp.Poke(type="126", id=2003)
|
||||
assert poke.toDict() == {
|
||||
"type": "poke",
|
||||
"data": {"type": "126", "id": "2003"},
|
||||
}
|
||||
|
||||
|
||||
def test_poke_to_dict_keeps_legacy_qq_compatible():
|
||||
poke = Comp.Poke(type="poke", qq=2916963017)
|
||||
assert poke.toDict() == {
|
||||
"type": "poke",
|
||||
"data": {"type": "126", "id": "2916963017"},
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_respond_stage_treats_poke_with_target_as_non_empty():
|
||||
stage = RespondStage()
|
||||
chain = [Comp.Poke(type="126", id=2003)]
|
||||
assert await stage._is_empty_message_chain(chain) is False
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_aiocqhttp_parse_json_outputs_standard_poke_data():
|
||||
chain = MessageChain([Comp.Poke(type="126", id=2003)])
|
||||
data = await AiocqhttpMessageEvent._parse_onebot_json(chain)
|
||||
assert data == [{"type": "poke", "data": {"type": "126", "id": "2003"}}]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_aiocqhttp_send_message_dispatches_onebot_v11_poke_payload():
|
||||
bot = AsyncMock()
|
||||
chain = MessageChain([Comp.Poke(type="126", id=2003)])
|
||||
|
||||
await AiocqhttpMessageEvent.send_message(
|
||||
bot=bot,
|
||||
message_chain=chain,
|
||||
event=None,
|
||||
is_group=True,
|
||||
session_id="123456",
|
||||
)
|
||||
|
||||
bot.send_group_msg.assert_awaited_once_with(
|
||||
group_id=123456,
|
||||
message=[{"type": "poke", "data": {"type": "126", "id": "2003"}}],
|
||||
)
|
||||
Reference in New Issue
Block a user