mirror of
https://github.com/nonebot/nonebot2.git
synced 2025-07-28 00:31:14 +00:00
⚡ improve ding adapter
add tests/test_ding.py add some log
This commit is contained in:
@ -19,6 +19,8 @@ from .event import Event, MessageEvent, PrivateMessageEvent, GroupMessageEvent,
|
||||
if TYPE_CHECKING:
|
||||
from nonebot.drivers import Driver
|
||||
|
||||
SEND_BY_SESSION_WEBHOOK = "send_by_sessionWebhook"
|
||||
|
||||
|
||||
class Bot(BaseBot):
|
||||
"""
|
||||
@ -89,7 +91,7 @@ class Bot(BaseBot):
|
||||
else:
|
||||
raise ValueError("Unsupported conversation type")
|
||||
except Exception as e:
|
||||
log("Error", "Event Parser Error", e)
|
||||
log("ERROR", "Event Parser Error", e)
|
||||
return
|
||||
|
||||
try:
|
||||
@ -135,7 +137,7 @@ class Bot(BaseBot):
|
||||
|
||||
log("DEBUG", f"Calling API <y>{api}</y>")
|
||||
|
||||
if api == "send_message":
|
||||
if api == SEND_BY_SESSION_WEBHOOK:
|
||||
if event:
|
||||
# 确保 sessionWebhook 没有过期
|
||||
if int(datetime.now().timestamp()) > int(
|
||||
@ -208,10 +210,8 @@ class Bot(BaseBot):
|
||||
params.update(kwargs)
|
||||
|
||||
if at_sender and event.conversationType != ConversationType.private:
|
||||
params[
|
||||
"message"] = f"@{event.senderId} " + msg + MessageSegment.atMobiles(
|
||||
event.senderId)
|
||||
params["message"] = f"@{event.senderNick} " + msg
|
||||
else:
|
||||
params["message"] = msg
|
||||
|
||||
return await self.call_api("send_message", **params)
|
||||
return await self.call_api(SEND_BY_SESSION_WEBHOOK, **params)
|
||||
|
@ -2,9 +2,8 @@ from enum import Enum
|
||||
from typing import List, Optional
|
||||
from typing_extensions import Literal
|
||||
|
||||
from pydantic import BaseModel
|
||||
from pydantic import BaseModel, root_validator
|
||||
|
||||
from nonebot.utils import escape_tag
|
||||
from nonebot.typing import overrides
|
||||
from nonebot.adapters import Event as BaseEvent
|
||||
|
||||
@ -27,27 +26,27 @@ class Event(BaseEvent):
|
||||
|
||||
@overrides(BaseEvent)
|
||||
def get_event_name(self) -> str:
|
||||
raise ValueError("Event has no type!")
|
||||
raise ValueError("Event has no name!")
|
||||
|
||||
@overrides(BaseEvent)
|
||||
def get_event_description(self) -> str:
|
||||
raise ValueError("Event has no type!")
|
||||
raise ValueError("Event has no description!")
|
||||
|
||||
@overrides(BaseEvent)
|
||||
def get_message(self) -> "Message":
|
||||
raise ValueError("Event has no type!")
|
||||
raise ValueError("Event has no message!")
|
||||
|
||||
@overrides(BaseEvent)
|
||||
def get_plaintext(self) -> str:
|
||||
raise ValueError("Event has no type!")
|
||||
raise ValueError("Event has no plaintext!")
|
||||
|
||||
@overrides(BaseEvent)
|
||||
def get_user_id(self) -> str:
|
||||
raise ValueError("Event has no type!")
|
||||
raise ValueError("Event has no user_id!")
|
||||
|
||||
@overrides(BaseEvent)
|
||||
def get_session_id(self) -> str:
|
||||
raise ValueError("Event has no type!")
|
||||
raise ValueError("Event has no session_id!")
|
||||
|
||||
@overrides(BaseEvent)
|
||||
def is_tome(self) -> bool:
|
||||
@ -82,6 +81,21 @@ class MessageEvent(Event):
|
||||
sessionWebhookExpiredTime: int
|
||||
isAdmin: bool
|
||||
|
||||
message: Message
|
||||
|
||||
@root_validator(pre=True)
|
||||
def gen_message(cls, values: dict):
|
||||
assert "msgtype" in values, "msgtype must be specified"
|
||||
# 其实目前钉钉机器人只能接收到 text 类型的消息
|
||||
assert values[
|
||||
"msgtype"] in values, f"{values['msgtype']} must be specified"
|
||||
content = values[values['msgtype']]['content']
|
||||
# 如果是被 @,第一个字符将会为空格,移除特殊情况
|
||||
if content[0] == ' ':
|
||||
content = content[1:]
|
||||
values["message"] = content
|
||||
return values
|
||||
|
||||
@overrides(Event)
|
||||
def get_type(self) -> Literal["message", "notice", "request", "meta_event"]:
|
||||
return "message"
|
||||
@ -94,6 +108,10 @@ class MessageEvent(Event):
|
||||
def get_event_description(self) -> str:
|
||||
return f'Message[{self.msgtype}] {self.msgId} from {self.senderId} "{self.text.content}"'
|
||||
|
||||
@overrides(BaseEvent)
|
||||
def get_message(self) -> Message:
|
||||
return self.message
|
||||
|
||||
@overrides(BaseEvent)
|
||||
def get_plaintext(self) -> str:
|
||||
return self.text.content
|
||||
|
@ -37,7 +37,7 @@ class ActionFailed(BaseActionFailed, DingAdapterException):
|
||||
self.errmsg = errmsg
|
||||
|
||||
def __repr__(self):
|
||||
return f"<ApiError errcode={self.errcode} errmsg={self.errmsg}>"
|
||||
return f"<ApiError errcode={self.errcode} errmsg=\"{self.errmsg}\">"
|
||||
|
||||
def __str__(self):
|
||||
return self.__repr__()
|
||||
|
@ -1,7 +1,8 @@
|
||||
from typing import Any, Dict, Union, Iterable
|
||||
|
||||
from nonebot.adapters import Message as BaseMessage, MessageSegment as BaseMessageSegment
|
||||
|
||||
from copy import copy
|
||||
|
||||
|
||||
class MessageSegment(BaseMessageSegment):
|
||||
"""
|
||||
@ -39,6 +40,16 @@ class MessageSegment(BaseMessageSegment):
|
||||
def text(text: str) -> "MessageSegment":
|
||||
return MessageSegment("text", {"content": text})
|
||||
|
||||
@staticmethod
|
||||
def image(picURL: str) -> "MessageSegment":
|
||||
return MessageSegment("image", {"picURL": picURL})
|
||||
|
||||
@staticmethod
|
||||
def extension(dict_: dict) -> "MessageSegment":
|
||||
""""标记 text 文本的 extension 属性,需要与 text 消息段相加。
|
||||
"""
|
||||
return MessageSegment("extension", dict_)
|
||||
|
||||
@staticmethod
|
||||
def markdown(title: str, text: str) -> "MessageSegment":
|
||||
return MessageSegment(
|
||||
@ -50,21 +61,21 @@ class MessageSegment(BaseMessageSegment):
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def actionCardSingleBtn(title: str, text: str, btnTitle: str,
|
||||
btnUrl) -> "MessageSegment":
|
||||
def actionCardSingleBtn(title: str, text: str, singleTitle: str,
|
||||
singleURL) -> "MessageSegment":
|
||||
return MessageSegment(
|
||||
"actionCard", {
|
||||
"title": title,
|
||||
"text": text,
|
||||
"singleTitle": btnTitle,
|
||||
"singleURL": btnUrl
|
||||
"singleTitle": singleTitle,
|
||||
"singleURL": singleURL
|
||||
})
|
||||
|
||||
@staticmethod
|
||||
def actionCardMultiBtns(
|
||||
title: str,
|
||||
text: str,
|
||||
btns: list = [],
|
||||
btns: list,
|
||||
hideAvatar: bool = False,
|
||||
btnOrientation: str = '1',
|
||||
) -> "MessageSegment":
|
||||
@ -85,7 +96,7 @@ class MessageSegment(BaseMessageSegment):
|
||||
})
|
||||
|
||||
@staticmethod
|
||||
def feedCard(links: list = []) -> "MessageSegment":
|
||||
def feedCard(links: list) -> "MessageSegment":
|
||||
"""
|
||||
:参数:
|
||||
|
||||
@ -94,9 +105,19 @@ class MessageSegment(BaseMessageSegment):
|
||||
return MessageSegment("feedCard", {"links": links})
|
||||
|
||||
@staticmethod
|
||||
def empty() -> "MessageSegment":
|
||||
"""不想回复消息到群里"""
|
||||
return MessageSegment("empty", {})
|
||||
def raw(data) -> "MessageSegment":
|
||||
return MessageSegment('raw', data)
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
# 让用户可以直接发送原始的消息格式
|
||||
if self.type == "raw":
|
||||
return copy(self.data)
|
||||
|
||||
# 不属于消息内容,只是作为消息段的辅助
|
||||
if self.type in ["at", "extension"]:
|
||||
return {self.type: copy(self.data)}
|
||||
|
||||
return {"msgtype": self.type, self.type: copy(self.data)}
|
||||
|
||||
|
||||
class Message(BaseMessage):
|
||||
@ -104,10 +125,6 @@ class Message(BaseMessage):
|
||||
钉钉 协议 Message 适配。
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def _validate(cls, value):
|
||||
return cls(value)
|
||||
|
||||
@staticmethod
|
||||
def _construct(msg: Union[str, dict, list]) -> Iterable[MessageSegment]:
|
||||
if isinstance(msg, dict):
|
||||
@ -121,23 +138,11 @@ class Message(BaseMessage):
|
||||
def _produce(self) -> dict:
|
||||
data = {}
|
||||
for segment in self:
|
||||
if segment.type == "text":
|
||||
data["msgtype"] = "text"
|
||||
# text 可以和 text 合并
|
||||
if segment.type == "text" and data.get("msgtype") == 'text':
|
||||
data.setdefault("text", {})
|
||||
data["text"]["content"] = data["text"].setdefault(
|
||||
"content", "") + segment.data["content"]
|
||||
elif segment.type == "markdown":
|
||||
data["msgtype"] = "markdown"
|
||||
data.setdefault("markdown", {})
|
||||
data["markdown"]["text"] = data["markdown"].setdefault(
|
||||
"content", "") + segment.data["content"]
|
||||
elif segment.type == "empty":
|
||||
data["msgtype"] = "empty"
|
||||
elif segment.type == "at" and "atMobiles" in segment.data:
|
||||
data.setdefault("at", {})
|
||||
data["at"]["atMobiles"] = data["at"].setdefault(
|
||||
"atMobiles", []) + segment.data["atMobiles"]
|
||||
elif segment.data:
|
||||
data.setdefault(segment.type, {})
|
||||
data[segment.type].update(segment.data)
|
||||
else:
|
||||
data.update(segment.to_dict())
|
||||
return data
|
||||
|
Reference in New Issue
Block a user