mirror of
https://github.com/nonebot/nonebot2.git
synced 2025-01-19 09:38:21 +08:00
⚡ improve ding adapter
add tests/test_ding.py add some log
This commit is contained in:
parent
3cb2b44130
commit
086a998b20
@ -19,6 +19,8 @@ from .event import Event, MessageEvent, PrivateMessageEvent, GroupMessageEvent,
|
|||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from nonebot.drivers import Driver
|
from nonebot.drivers import Driver
|
||||||
|
|
||||||
|
SEND_BY_SESSION_WEBHOOK = "send_by_sessionWebhook"
|
||||||
|
|
||||||
|
|
||||||
class Bot(BaseBot):
|
class Bot(BaseBot):
|
||||||
"""
|
"""
|
||||||
@ -89,7 +91,7 @@ class Bot(BaseBot):
|
|||||||
else:
|
else:
|
||||||
raise ValueError("Unsupported conversation type")
|
raise ValueError("Unsupported conversation type")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log("Error", "Event Parser Error", e)
|
log("ERROR", "Event Parser Error", e)
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -135,7 +137,7 @@ class Bot(BaseBot):
|
|||||||
|
|
||||||
log("DEBUG", f"Calling API <y>{api}</y>")
|
log("DEBUG", f"Calling API <y>{api}</y>")
|
||||||
|
|
||||||
if api == "send_message":
|
if api == SEND_BY_SESSION_WEBHOOK:
|
||||||
if event:
|
if event:
|
||||||
# 确保 sessionWebhook 没有过期
|
# 确保 sessionWebhook 没有过期
|
||||||
if int(datetime.now().timestamp()) > int(
|
if int(datetime.now().timestamp()) > int(
|
||||||
@ -208,10 +210,8 @@ class Bot(BaseBot):
|
|||||||
params.update(kwargs)
|
params.update(kwargs)
|
||||||
|
|
||||||
if at_sender and event.conversationType != ConversationType.private:
|
if at_sender and event.conversationType != ConversationType.private:
|
||||||
params[
|
params["message"] = f"@{event.senderNick} " + msg
|
||||||
"message"] = f"@{event.senderId} " + msg + MessageSegment.atMobiles(
|
|
||||||
event.senderId)
|
|
||||||
else:
|
else:
|
||||||
params["message"] = msg
|
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 import List, Optional
|
||||||
from typing_extensions import Literal
|
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.typing import overrides
|
||||||
from nonebot.adapters import Event as BaseEvent
|
from nonebot.adapters import Event as BaseEvent
|
||||||
|
|
||||||
@ -27,27 +26,27 @@ class Event(BaseEvent):
|
|||||||
|
|
||||||
@overrides(BaseEvent)
|
@overrides(BaseEvent)
|
||||||
def get_event_name(self) -> str:
|
def get_event_name(self) -> str:
|
||||||
raise ValueError("Event has no type!")
|
raise ValueError("Event has no name!")
|
||||||
|
|
||||||
@overrides(BaseEvent)
|
@overrides(BaseEvent)
|
||||||
def get_event_description(self) -> str:
|
def get_event_description(self) -> str:
|
||||||
raise ValueError("Event has no type!")
|
raise ValueError("Event has no description!")
|
||||||
|
|
||||||
@overrides(BaseEvent)
|
@overrides(BaseEvent)
|
||||||
def get_message(self) -> "Message":
|
def get_message(self) -> "Message":
|
||||||
raise ValueError("Event has no type!")
|
raise ValueError("Event has no message!")
|
||||||
|
|
||||||
@overrides(BaseEvent)
|
@overrides(BaseEvent)
|
||||||
def get_plaintext(self) -> str:
|
def get_plaintext(self) -> str:
|
||||||
raise ValueError("Event has no type!")
|
raise ValueError("Event has no plaintext!")
|
||||||
|
|
||||||
@overrides(BaseEvent)
|
@overrides(BaseEvent)
|
||||||
def get_user_id(self) -> str:
|
def get_user_id(self) -> str:
|
||||||
raise ValueError("Event has no type!")
|
raise ValueError("Event has no user_id!")
|
||||||
|
|
||||||
@overrides(BaseEvent)
|
@overrides(BaseEvent)
|
||||||
def get_session_id(self) -> str:
|
def get_session_id(self) -> str:
|
||||||
raise ValueError("Event has no type!")
|
raise ValueError("Event has no session_id!")
|
||||||
|
|
||||||
@overrides(BaseEvent)
|
@overrides(BaseEvent)
|
||||||
def is_tome(self) -> bool:
|
def is_tome(self) -> bool:
|
||||||
@ -82,6 +81,21 @@ class MessageEvent(Event):
|
|||||||
sessionWebhookExpiredTime: int
|
sessionWebhookExpiredTime: int
|
||||||
isAdmin: bool
|
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)
|
@overrides(Event)
|
||||||
def get_type(self) -> Literal["message", "notice", "request", "meta_event"]:
|
def get_type(self) -> Literal["message", "notice", "request", "meta_event"]:
|
||||||
return "message"
|
return "message"
|
||||||
@ -94,6 +108,10 @@ class MessageEvent(Event):
|
|||||||
def get_event_description(self) -> str:
|
def get_event_description(self) -> str:
|
||||||
return f'Message[{self.msgtype}] {self.msgId} from {self.senderId} "{self.text.content}"'
|
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)
|
@overrides(BaseEvent)
|
||||||
def get_plaintext(self) -> str:
|
def get_plaintext(self) -> str:
|
||||||
return self.text.content
|
return self.text.content
|
||||||
|
@ -37,7 +37,7 @@ class ActionFailed(BaseActionFailed, DingAdapterException):
|
|||||||
self.errmsg = errmsg
|
self.errmsg = errmsg
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"<ApiError errcode={self.errcode} errmsg={self.errmsg}>"
|
return f"<ApiError errcode={self.errcode} errmsg=\"{self.errmsg}\">"
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.__repr__()
|
return self.__repr__()
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
from typing import Any, Dict, Union, Iterable
|
from typing import Any, Dict, Union, Iterable
|
||||||
|
|
||||||
from nonebot.adapters import Message as BaseMessage, MessageSegment as BaseMessageSegment
|
from nonebot.adapters import Message as BaseMessage, MessageSegment as BaseMessageSegment
|
||||||
|
|
||||||
|
from copy import copy
|
||||||
|
|
||||||
|
|
||||||
class MessageSegment(BaseMessageSegment):
|
class MessageSegment(BaseMessageSegment):
|
||||||
"""
|
"""
|
||||||
@ -39,6 +40,16 @@ class MessageSegment(BaseMessageSegment):
|
|||||||
def text(text: str) -> "MessageSegment":
|
def text(text: str) -> "MessageSegment":
|
||||||
return MessageSegment("text", {"content": text})
|
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
|
@staticmethod
|
||||||
def markdown(title: str, text: str) -> "MessageSegment":
|
def markdown(title: str, text: str) -> "MessageSegment":
|
||||||
return MessageSegment(
|
return MessageSegment(
|
||||||
@ -50,21 +61,21 @@ class MessageSegment(BaseMessageSegment):
|
|||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def actionCardSingleBtn(title: str, text: str, btnTitle: str,
|
def actionCardSingleBtn(title: str, text: str, singleTitle: str,
|
||||||
btnUrl) -> "MessageSegment":
|
singleURL) -> "MessageSegment":
|
||||||
return MessageSegment(
|
return MessageSegment(
|
||||||
"actionCard", {
|
"actionCard", {
|
||||||
"title": title,
|
"title": title,
|
||||||
"text": text,
|
"text": text,
|
||||||
"singleTitle": btnTitle,
|
"singleTitle": singleTitle,
|
||||||
"singleURL": btnUrl
|
"singleURL": singleURL
|
||||||
})
|
})
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def actionCardMultiBtns(
|
def actionCardMultiBtns(
|
||||||
title: str,
|
title: str,
|
||||||
text: str,
|
text: str,
|
||||||
btns: list = [],
|
btns: list,
|
||||||
hideAvatar: bool = False,
|
hideAvatar: bool = False,
|
||||||
btnOrientation: str = '1',
|
btnOrientation: str = '1',
|
||||||
) -> "MessageSegment":
|
) -> "MessageSegment":
|
||||||
@ -85,7 +96,7 @@ class MessageSegment(BaseMessageSegment):
|
|||||||
})
|
})
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def feedCard(links: list = []) -> "MessageSegment":
|
def feedCard(links: list) -> "MessageSegment":
|
||||||
"""
|
"""
|
||||||
:参数:
|
:参数:
|
||||||
|
|
||||||
@ -94,9 +105,19 @@ class MessageSegment(BaseMessageSegment):
|
|||||||
return MessageSegment("feedCard", {"links": links})
|
return MessageSegment("feedCard", {"links": links})
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def empty() -> "MessageSegment":
|
def raw(data) -> "MessageSegment":
|
||||||
"""不想回复消息到群里"""
|
return MessageSegment('raw', data)
|
||||||
return MessageSegment("empty", {})
|
|
||||||
|
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):
|
class Message(BaseMessage):
|
||||||
@ -104,10 +125,6 @@ class Message(BaseMessage):
|
|||||||
钉钉 协议 Message 适配。
|
钉钉 协议 Message 适配。
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _validate(cls, value):
|
|
||||||
return cls(value)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _construct(msg: Union[str, dict, list]) -> Iterable[MessageSegment]:
|
def _construct(msg: Union[str, dict, list]) -> Iterable[MessageSegment]:
|
||||||
if isinstance(msg, dict):
|
if isinstance(msg, dict):
|
||||||
@ -121,23 +138,11 @@ class Message(BaseMessage):
|
|||||||
def _produce(self) -> dict:
|
def _produce(self) -> dict:
|
||||||
data = {}
|
data = {}
|
||||||
for segment in self:
|
for segment in self:
|
||||||
if segment.type == "text":
|
# text 可以和 text 合并
|
||||||
data["msgtype"] = "text"
|
if segment.type == "text" and data.get("msgtype") == 'text':
|
||||||
data.setdefault("text", {})
|
data.setdefault("text", {})
|
||||||
data["text"]["content"] = data["text"].setdefault(
|
data["text"]["content"] = data["text"].setdefault(
|
||||||
"content", "") + segment.data["content"]
|
"content", "") + segment.data["content"]
|
||||||
elif segment.type == "markdown":
|
else:
|
||||||
data["msgtype"] = "markdown"
|
data.update(segment.to_dict())
|
||||||
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)
|
|
||||||
return data
|
return data
|
||||||
|
@ -113,7 +113,7 @@ class Matcher(metaclass=MatcherMeta):
|
|||||||
self.state = self._default_state.copy()
|
self.state = self._default_state.copy()
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return (f"<Matcher from {self.module or 'unknow'}, type={self.type}, "
|
return (f"<Matcher from {self.module or 'unknown'}, type={self.type}, "
|
||||||
f"priority={self.priority}, temp={self.temp}>")
|
f"priority={self.priority}, temp={self.temp}>")
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
@ -460,13 +460,23 @@ class Matcher(metaclass=MatcherMeta):
|
|||||||
if not hasattr(handler, "__params__"):
|
if not hasattr(handler, "__params__"):
|
||||||
self.process_handler(handler)
|
self.process_handler(handler)
|
||||||
params = getattr(handler, "__params__")
|
params = getattr(handler, "__params__")
|
||||||
|
|
||||||
BotType = ((params["bot"] is not inspect.Parameter.empty) and
|
BotType = ((params["bot"] is not inspect.Parameter.empty) and
|
||||||
inspect.isclass(params["bot"]) and params["bot"])
|
inspect.isclass(params["bot"]) and params["bot"])
|
||||||
|
if BotType and not isinstance(bot, BotType):
|
||||||
|
logger.info(
|
||||||
|
f"Matcher {self} bot type {type(bot)} not match annotation {BotType}, ignored"
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
EventType = ((params["event"] is not inspect.Parameter.empty) and
|
EventType = ((params["event"] is not inspect.Parameter.empty) and
|
||||||
inspect.isclass(params["event"]) and params["event"])
|
inspect.isclass(params["event"]) and params["event"])
|
||||||
if (BotType and not isinstance(bot, BotType)) or (
|
if EventType and not isinstance(event, EventType):
|
||||||
EventType and not isinstance(event, EventType)):
|
logger.info(
|
||||||
|
f"Matcher {self} event type {type(event)} not match annotation {EventType}, ignored"
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
args = {"bot": bot, "event": event, "state": state, "matcher": self}
|
args = {"bot": bot, "event": event, "state": state, "matcher": self}
|
||||||
await handler(
|
await handler(
|
||||||
**{k: v for k, v in args.items() if params[k] is not None})
|
**{k: v for k, v in args.items() if params[k] is not None})
|
||||||
|
160
tests/test_plugins/test_ding.py
Normal file
160
tests/test_plugins/test_ding.py
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
from nonebot.rule import to_me
|
||||||
|
from nonebot.plugin import on_command
|
||||||
|
from nonebot.adapters.ding import Bot as DingBot, MessageSegment, MessageEvent
|
||||||
|
|
||||||
|
markdown = on_command("markdown", to_me())
|
||||||
|
|
||||||
|
|
||||||
|
@markdown.handle()
|
||||||
|
async def test_handler(bot: DingBot):
|
||||||
|
message = MessageSegment.markdown(
|
||||||
|
"Hello, This is NoneBot",
|
||||||
|
"#### NoneBot \n> Nonebot 是一款高性能的 Python 机器人框架\n> ![screenshot](https://v2.nonebot.dev/logo.png)\n> [GitHub 仓库地址](https://github.com/nonebot/nonebot2) \n"
|
||||||
|
)
|
||||||
|
await markdown.finish(message)
|
||||||
|
|
||||||
|
|
||||||
|
actionCardSingleBtn = on_command("actionCardSingleBtn", to_me())
|
||||||
|
|
||||||
|
|
||||||
|
@actionCardSingleBtn.handle()
|
||||||
|
async def test_handler(bot: DingBot):
|
||||||
|
message = MessageSegment.actionCardSingleBtn(
|
||||||
|
title="打造一间咖啡厅",
|
||||||
|
text=
|
||||||
|
"![screenshot](https://img.alicdn.com/tfs/TB1NwmBEL9TBuNjy1zbXXXpepXa-2400-1218.png) \n #### 乔布斯 20 年前想打造的苹果咖啡厅 \n\n Apple Store 的设计正从原来满满的科技感走向生活化,而其生活化的走向其实可以追溯到 20 年前苹果一个建立咖啡馆的计划",
|
||||||
|
singleTitle="阅读全文",
|
||||||
|
singleURL="https://www.dingtalk.com/")
|
||||||
|
await actionCardSingleBtn.finish(message)
|
||||||
|
|
||||||
|
|
||||||
|
actionCard = on_command("actionCard", to_me())
|
||||||
|
|
||||||
|
|
||||||
|
@actionCard.handle()
|
||||||
|
async def test_handler(bot: DingBot):
|
||||||
|
message = MessageSegment.raw({
|
||||||
|
"msgtype": "actionCard",
|
||||||
|
"actionCard": {
|
||||||
|
"title":
|
||||||
|
"乔布斯 20 年前想打造一间苹果咖啡厅,而它正是 Apple Store 的前身",
|
||||||
|
"text":
|
||||||
|
"![screenshot](https://img.alicdn.com/tfs/TB1NwmBEL9TBuNjy1zbXXXpepXa-2400-1218.png) \n\n #### 乔布斯 20 年前想打造的苹果咖啡厅 \n\n Apple Store 的设计正从原来满满的科技感走向生活化,而其生活化的走向其实可以追溯到 20 年前苹果一个建立咖啡馆的计划",
|
||||||
|
"hideAvatar":
|
||||||
|
"0",
|
||||||
|
"btnOrientation":
|
||||||
|
"0",
|
||||||
|
"btns": [{
|
||||||
|
"title": "内容不错",
|
||||||
|
"actionURL": "https://www.dingtalk.com/"
|
||||||
|
}, {
|
||||||
|
"title": "不感兴趣",
|
||||||
|
"actionURL": "https://www.dingtalk.com/"
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
await actionCard.finish(message)
|
||||||
|
|
||||||
|
|
||||||
|
feedCard = on_command("feedCard", to_me())
|
||||||
|
|
||||||
|
|
||||||
|
@feedCard.handle()
|
||||||
|
async def test_handler(bot: DingBot):
|
||||||
|
message = MessageSegment.raw({
|
||||||
|
"msgtype": "feedCard",
|
||||||
|
"feedCard": {
|
||||||
|
"links": [{
|
||||||
|
"title":
|
||||||
|
"时代的火车向前开1",
|
||||||
|
"messageURL":
|
||||||
|
"https://www.dingtalk.com/",
|
||||||
|
"picURL":
|
||||||
|
"https://img.alicdn.com/tfs/TB1NwmBEL9TBuNjy1zbXXXpepXa-2400-1218.png"
|
||||||
|
}, {
|
||||||
|
"title":
|
||||||
|
"时代的火车向前开2",
|
||||||
|
"messageURL":
|
||||||
|
"https://www.dingtalk.com/",
|
||||||
|
"picURL":
|
||||||
|
"https://img.alicdn.com/tfs/TB1NwmBEL9TBuNjy1zbXXXpepXa-2400-1218.png"
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
await feedCard.finish(message)
|
||||||
|
|
||||||
|
|
||||||
|
atme = on_command("atme", to_me())
|
||||||
|
|
||||||
|
|
||||||
|
@atme.handle()
|
||||||
|
async def test_handler(bot: DingBot, event: MessageEvent):
|
||||||
|
message = f"@{event.senderNick} at you" + MessageSegment.atMobiles(
|
||||||
|
"13800000001")
|
||||||
|
await atme.finish(message)
|
||||||
|
|
||||||
|
|
||||||
|
image = on_command("image", to_me())
|
||||||
|
|
||||||
|
|
||||||
|
@image.handle()
|
||||||
|
async def test_handler(bot: DingBot, event: MessageEvent):
|
||||||
|
message = MessageSegment.image(
|
||||||
|
"https://static-aliyun-doc.oss-accelerate.aliyuncs.com/assets/img/zh-CN/0634199951/p158167.png"
|
||||||
|
)
|
||||||
|
await image.finish(message)
|
||||||
|
|
||||||
|
|
||||||
|
textAdd = on_command("t", to_me())
|
||||||
|
|
||||||
|
|
||||||
|
@textAdd.handle()
|
||||||
|
async def test_handler(bot: DingBot, event: MessageEvent):
|
||||||
|
message = "第一段消息\n" + MessageSegment.text("asdawefaefa\n")
|
||||||
|
await textAdd.send(message)
|
||||||
|
|
||||||
|
message = message + MessageSegment.text("第二段消息\n")
|
||||||
|
await textAdd.send(message)
|
||||||
|
|
||||||
|
message = message + MessageSegment.text(
|
||||||
|
"\n第三段消息\n") + "adfkasfkhsdkfahskdjasdashdkjasdf"
|
||||||
|
message = message + MessageSegment.extension({
|
||||||
|
"text_type": "code_snippet",
|
||||||
|
"code_language": "C#"
|
||||||
|
})
|
||||||
|
await textAdd.send(message)
|
||||||
|
|
||||||
|
|
||||||
|
code = on_command("code", to_me())
|
||||||
|
|
||||||
|
|
||||||
|
@code.handle()
|
||||||
|
async def test_handler(bot: DingBot, event: MessageEvent):
|
||||||
|
raw = MessageSegment.raw({
|
||||||
|
"msgtype": "text",
|
||||||
|
"text": {
|
||||||
|
"content": 'print("hello world")'
|
||||||
|
},
|
||||||
|
"extension": {
|
||||||
|
"text_type": "code_snippet",
|
||||||
|
"code_language": "Python",
|
||||||
|
}
|
||||||
|
})
|
||||||
|
await code.send(raw)
|
||||||
|
message = MessageSegment.text("""using System;
|
||||||
|
|
||||||
|
namespace HelloWorld
|
||||||
|
{
|
||||||
|
class Program
|
||||||
|
{
|
||||||
|
static void Main(string[] args)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Hello World!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}""")
|
||||||
|
message += MessageSegment.extension({
|
||||||
|
"text_type": "code_snippet",
|
||||||
|
"code_language": "C#"
|
||||||
|
})
|
||||||
|
await code.finish(message)
|
@ -11,8 +11,3 @@ test_command = on_startswith("hello", to_me(), permission=SUPERUSER)
|
|||||||
@test_command.handle()
|
@test_command.handle()
|
||||||
async def test_handler(bot: CQHTTPBot):
|
async def test_handler(bot: CQHTTPBot):
|
||||||
await test_command.finish("cqhttp hello")
|
await test_command.finish("cqhttp hello")
|
||||||
|
|
||||||
|
|
||||||
@test_command.handle()
|
|
||||||
async def test_handler(bot: DingBot):
|
|
||||||
await test_command.finish("ding hello")
|
|
||||||
|
Loading…
Reference in New Issue
Block a user