mirror of
https://github.com/nonebot/nonebot2.git
synced 2025-07-29 17:27:41 +00:00
🏗️ change nonebot project structure
This commit is contained in:
@ -0,0 +1,29 @@
|
||||
"""
|
||||
\:\:\: warning
|
||||
事件中为了使代码更加整洁, 我们采用了与PEP8相符的命名规则取代Mirai原有的驼峰命名
|
||||
|
||||
部分字段可能与文档在符号上不一致
|
||||
\:\:\:
|
||||
"""
|
||||
from .base import (Event, GroupChatInfo, GroupInfo, PrivateChatInfo,
|
||||
UserPermission)
|
||||
from .message import *
|
||||
from .notice import *
|
||||
from .request import *
|
||||
|
||||
__all__ = [
|
||||
'Event', 'GroupChatInfo', 'GroupInfo', 'PrivateChatInfo', 'UserPermission',
|
||||
'MessageSource', 'MessageEvent', 'GroupMessage', 'FriendMessage',
|
||||
'TempMessage', 'NoticeEvent', 'MuteEvent', 'BotMuteEvent', 'BotUnmuteEvent',
|
||||
'MemberMuteEvent', 'MemberUnmuteEvent', 'BotJoinGroupEvent',
|
||||
'BotLeaveEventActive', 'BotLeaveEventKick', 'MemberJoinEvent',
|
||||
'MemberLeaveEventKick', 'MemberLeaveEventQuit', 'FriendRecallEvent',
|
||||
'GroupRecallEvent', 'GroupStateChangeEvent', 'GroupNameChangeEvent',
|
||||
'GroupEntranceAnnouncementChangeEvent', 'GroupMuteAllEvent',
|
||||
'GroupAllowAnonymousChatEvent', 'GroupAllowConfessTalkEvent',
|
||||
'GroupAllowMemberInviteEvent', 'MemberStateChangeEvent',
|
||||
'MemberCardChangeEvent', 'MemberSpecialTitleChangeEvent',
|
||||
'BotGroupPermissionChangeEvent', 'MemberPermissionChangeEvent',
|
||||
'RequestEvent', 'NewFriendRequestEvent', 'MemberJoinRequestEvent',
|
||||
'BotInvitedJoinGroupRequestEvent'
|
||||
]
|
@ -0,0 +1,133 @@
|
||||
import json
|
||||
from enum import Enum
|
||||
from typing import Any, Dict, Optional, Type
|
||||
|
||||
from pydantic import BaseModel, Field, ValidationError
|
||||
from typing_extensions import Literal
|
||||
|
||||
from nonebot.adapters import Event as BaseEvent
|
||||
from nonebot.adapters import Message as BaseMessage
|
||||
from nonebot.log import logger
|
||||
from nonebot.typing import overrides
|
||||
|
||||
|
||||
class UserPermission(str, Enum):
|
||||
"""
|
||||
:说明:
|
||||
|
||||
用户权限枚举类
|
||||
|
||||
* ``OWNER``: 群主
|
||||
* ``ADMINISTRATOR``: 群管理
|
||||
* ``MEMBER``: 普通群成员
|
||||
"""
|
||||
OWNER = 'OWNER'
|
||||
ADMINISTRATOR = 'ADMINISTRATOR'
|
||||
MEMBER = 'MEMBER'
|
||||
|
||||
|
||||
class GroupInfo(BaseModel):
|
||||
id: int
|
||||
name: str
|
||||
permission: UserPermission
|
||||
|
||||
|
||||
class GroupChatInfo(BaseModel):
|
||||
id: int
|
||||
name: str = Field(alias='memberName')
|
||||
permission: UserPermission
|
||||
group: GroupInfo
|
||||
|
||||
|
||||
class PrivateChatInfo(BaseModel):
|
||||
id: int
|
||||
nickname: str
|
||||
remark: str
|
||||
|
||||
|
||||
class Event(BaseEvent):
|
||||
"""
|
||||
mirai-api-http 协议事件,字段与 mirai-api-http 一致。各事件字段参考 `mirai-api-http 事件类型`_
|
||||
|
||||
.. _mirai-api-http 事件类型:
|
||||
https://github.com/project-mirai/mirai-api-http/blob/master/docs/EventType.md
|
||||
"""
|
||||
self_id: int
|
||||
type: str
|
||||
|
||||
@classmethod
|
||||
def new(cls, data: Dict[str, Any]) -> "Event":
|
||||
"""
|
||||
此事件类的工厂函数, 能够通过事件数据选择合适的子类进行序列化
|
||||
"""
|
||||
type = data['type']
|
||||
|
||||
def all_subclasses(cls: Type[Event]):
|
||||
return set(cls.__subclasses__()).union(
|
||||
[s for c in cls.__subclasses__() for s in all_subclasses(c)])
|
||||
|
||||
event_class: Optional[Type[Event]] = None
|
||||
for subclass in all_subclasses(cls):
|
||||
if subclass.__name__ != type:
|
||||
continue
|
||||
event_class = subclass
|
||||
|
||||
if event_class is None:
|
||||
return Event.parse_obj(data)
|
||||
|
||||
while issubclass(event_class, Event):
|
||||
try:
|
||||
return event_class.parse_obj(data)
|
||||
except ValidationError as e:
|
||||
logger.info(
|
||||
f'Failed to parse {data} to class {event_class.__name__}: '
|
||||
f'{e.errors()!r}. Fallback to parent class.')
|
||||
event_class = event_class.__base__
|
||||
|
||||
raise ValueError(f'Failed to serialize {data}.')
|
||||
|
||||
@overrides(BaseEvent)
|
||||
def get_type(self) -> Literal["message", "notice", "request", "meta_event"]:
|
||||
from . import message, notice, request, meta
|
||||
if isinstance(self, message.MessageEvent):
|
||||
return 'message'
|
||||
elif isinstance(self, notice.NoticeEvent):
|
||||
return 'notice'
|
||||
elif isinstance(self, request.RequestEvent):
|
||||
return 'request'
|
||||
else:
|
||||
return 'meta_event'
|
||||
|
||||
@overrides(BaseEvent)
|
||||
def get_event_name(self) -> str:
|
||||
return self.type
|
||||
|
||||
@overrides(BaseEvent)
|
||||
def get_event_description(self) -> str:
|
||||
return str(self.normalize_dict())
|
||||
|
||||
@overrides(BaseEvent)
|
||||
def get_message(self) -> BaseMessage:
|
||||
raise ValueError("Event has no message!")
|
||||
|
||||
@overrides(BaseEvent)
|
||||
def get_plaintext(self) -> str:
|
||||
raise ValueError("Event has no message!")
|
||||
|
||||
@overrides(BaseEvent)
|
||||
def get_user_id(self) -> str:
|
||||
raise ValueError("Event has no message!")
|
||||
|
||||
@overrides(BaseEvent)
|
||||
def get_session_id(self) -> str:
|
||||
raise ValueError("Event has no message!")
|
||||
|
||||
@overrides(BaseEvent)
|
||||
def is_tome(self) -> bool:
|
||||
return False
|
||||
|
||||
def normalize_dict(self, **kwargs) -> Dict[str, Any]:
|
||||
"""
|
||||
返回可以被json正常反序列化的结构体
|
||||
"""
|
||||
return json.loads(self.json(**kwargs))
|
@ -0,0 +1,85 @@
|
||||
from datetime import datetime
|
||||
from typing import Any, Optional
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from nonebot.typing import overrides
|
||||
|
||||
from ..message import MessageChain
|
||||
from .base import Event, GroupChatInfo, PrivateChatInfo
|
||||
|
||||
|
||||
class MessageSource(BaseModel):
|
||||
id: int
|
||||
time: datetime
|
||||
|
||||
|
||||
class MessageEvent(Event):
|
||||
"""消息事件基类"""
|
||||
message_chain: MessageChain = Field(alias='messageChain')
|
||||
source: Optional[MessageSource] = None
|
||||
sender: Any
|
||||
|
||||
@overrides(Event)
|
||||
def get_message(self) -> MessageChain:
|
||||
return self.message_chain
|
||||
|
||||
@overrides(Event)
|
||||
def get_plaintext(self) -> str:
|
||||
return self.message_chain.extract_plain_text()
|
||||
|
||||
@overrides(Event)
|
||||
def get_user_id(self) -> str:
|
||||
raise NotImplementedError
|
||||
|
||||
@overrides(Event)
|
||||
def get_session_id(self) -> str:
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class GroupMessage(MessageEvent):
|
||||
"""群消息事件"""
|
||||
sender: GroupChatInfo
|
||||
to_me: bool = False
|
||||
|
||||
@overrides(MessageEvent)
|
||||
def get_session_id(self) -> str:
|
||||
return f'group_{self.sender.group.id}_' + self.get_user_id()
|
||||
|
||||
@overrides(MessageEvent)
|
||||
def get_user_id(self) -> str:
|
||||
return str(self.sender.id)
|
||||
|
||||
@overrides(MessageEvent)
|
||||
def is_tome(self) -> bool:
|
||||
return self.to_me
|
||||
|
||||
|
||||
class FriendMessage(MessageEvent):
|
||||
"""好友消息事件"""
|
||||
sender: PrivateChatInfo
|
||||
|
||||
@overrides(MessageEvent)
|
||||
def get_user_id(self) -> str:
|
||||
return str(self.sender.id)
|
||||
|
||||
@overrides(MessageEvent)
|
||||
def get_session_id(self) -> str:
|
||||
return 'friend_' + self.get_user_id()
|
||||
|
||||
@overrides(MessageEvent)
|
||||
def is_tome(self) -> bool:
|
||||
return True
|
||||
|
||||
|
||||
class TempMessage(MessageEvent):
|
||||
"""临时会话消息事件"""
|
||||
sender: GroupChatInfo
|
||||
|
||||
@overrides(MessageEvent)
|
||||
def get_session_id(self) -> str:
|
||||
return f'temp_{self.sender.group.id}_' + self.get_user_id()
|
||||
|
||||
@overrides(MessageEvent)
|
||||
def is_tome(self) -> bool:
|
||||
return True
|
@ -0,0 +1,31 @@
|
||||
from .base import Event
|
||||
|
||||
|
||||
class MetaEvent(Event):
|
||||
"""元事件基类"""
|
||||
qq: int
|
||||
|
||||
|
||||
class BotOnlineEvent(MetaEvent):
|
||||
"""Bot登录成功"""
|
||||
pass
|
||||
|
||||
|
||||
class BotOfflineEventActive(MetaEvent):
|
||||
"""Bot主动离线"""
|
||||
pass
|
||||
|
||||
|
||||
class BotOfflineEventForce(MetaEvent):
|
||||
"""Bot被挤下线"""
|
||||
pass
|
||||
|
||||
|
||||
class BotOfflineEventDropped(MetaEvent):
|
||||
"""Bot被服务器断开或因网络问题而掉线"""
|
||||
pass
|
||||
|
||||
|
||||
class BotReloginEvent(MetaEvent):
|
||||
"""Bot主动重新登录"""
|
||||
pass
|
@ -0,0 +1,156 @@
|
||||
from typing import Any, Optional
|
||||
|
||||
from pydantic import Field
|
||||
|
||||
from .base import Event, GroupChatInfo, GroupInfo, UserPermission
|
||||
|
||||
|
||||
class NoticeEvent(Event):
|
||||
"""通知事件基类"""
|
||||
pass
|
||||
|
||||
|
||||
class MuteEvent(NoticeEvent):
|
||||
"""禁言类事件基类"""
|
||||
operator: GroupChatInfo
|
||||
|
||||
|
||||
class BotMuteEvent(MuteEvent):
|
||||
"""Bot被禁言"""
|
||||
pass
|
||||
|
||||
|
||||
class BotUnmuteEvent(MuteEvent):
|
||||
"""Bot被取消禁言"""
|
||||
pass
|
||||
|
||||
|
||||
class MemberMuteEvent(MuteEvent):
|
||||
"""群成员被禁言事件(该成员不是Bot)"""
|
||||
duration_seconds: int = Field(alias='durationSeconds')
|
||||
member: GroupChatInfo
|
||||
operator: Optional[GroupChatInfo] = None
|
||||
|
||||
|
||||
class MemberUnmuteEvent(MuteEvent):
|
||||
"""群成员被取消禁言事件(该成员不是Bot)"""
|
||||
member: GroupChatInfo
|
||||
operator: Optional[GroupChatInfo] = None
|
||||
|
||||
|
||||
class BotJoinGroupEvent(NoticeEvent):
|
||||
"""Bot加入了一个新群"""
|
||||
group: GroupInfo
|
||||
|
||||
|
||||
class BotLeaveEventActive(BotJoinGroupEvent):
|
||||
"""Bot主动退出一个群"""
|
||||
pass
|
||||
|
||||
|
||||
class BotLeaveEventKick(BotJoinGroupEvent):
|
||||
"""Bot被踢出一个群"""
|
||||
pass
|
||||
|
||||
|
||||
class MemberJoinEvent(NoticeEvent):
|
||||
"""新人入群的事件"""
|
||||
member: GroupChatInfo
|
||||
|
||||
|
||||
class MemberLeaveEventKick(MemberJoinEvent):
|
||||
"""成员被踢出群(该成员不是Bot)"""
|
||||
operator: Optional[GroupChatInfo] = None
|
||||
|
||||
|
||||
class MemberLeaveEventQuit(MemberJoinEvent):
|
||||
"""成员主动离群(该成员不是Bot)"""
|
||||
pass
|
||||
|
||||
|
||||
class FriendRecallEvent(NoticeEvent):
|
||||
"""好友消息撤回"""
|
||||
author_id: int = Field(alias='authorId')
|
||||
message_id: int = Field(alias='messageId')
|
||||
time: int
|
||||
operator: int
|
||||
|
||||
|
||||
class GroupRecallEvent(FriendRecallEvent):
|
||||
"""群消息撤回"""
|
||||
group: GroupInfo
|
||||
operator: Optional[GroupChatInfo] = None
|
||||
|
||||
|
||||
class GroupStateChangeEvent(NoticeEvent):
|
||||
"""群变化事件基类"""
|
||||
origin: Any
|
||||
current: Any
|
||||
group: GroupInfo
|
||||
operator: Optional[GroupChatInfo] = None
|
||||
|
||||
|
||||
class GroupNameChangeEvent(GroupStateChangeEvent):
|
||||
"""某个群名改变"""
|
||||
origin: str
|
||||
current: str
|
||||
|
||||
|
||||
class GroupEntranceAnnouncementChangeEvent(GroupStateChangeEvent):
|
||||
"""某群入群公告改变"""
|
||||
origin: str
|
||||
current: str
|
||||
|
||||
|
||||
class GroupMuteAllEvent(GroupStateChangeEvent):
|
||||
"""全员禁言"""
|
||||
origin: bool
|
||||
current: bool
|
||||
|
||||
|
||||
class GroupAllowAnonymousChatEvent(GroupStateChangeEvent):
|
||||
"""匿名聊天"""
|
||||
origin: bool
|
||||
current: bool
|
||||
|
||||
|
||||
class GroupAllowConfessTalkEvent(GroupStateChangeEvent):
|
||||
"""坦白说"""
|
||||
origin: bool
|
||||
current: bool
|
||||
|
||||
|
||||
class GroupAllowMemberInviteEvent(GroupStateChangeEvent):
|
||||
"""允许群员邀请好友加群"""
|
||||
origin: bool
|
||||
current: bool
|
||||
|
||||
|
||||
class MemberStateChangeEvent(NoticeEvent):
|
||||
"""群成员变化事件基类"""
|
||||
member: GroupChatInfo
|
||||
operator: Optional[GroupChatInfo] = None
|
||||
|
||||
|
||||
class MemberCardChangeEvent(MemberStateChangeEvent):
|
||||
"""群名片改动"""
|
||||
origin: str
|
||||
current: str
|
||||
|
||||
|
||||
class MemberSpecialTitleChangeEvent(MemberStateChangeEvent):
|
||||
"""群头衔改动(只有群主有操作限权)"""
|
||||
origin: str
|
||||
current: str
|
||||
|
||||
|
||||
class BotGroupPermissionChangeEvent(MemberStateChangeEvent):
|
||||
"""Bot在群里的权限被改变"""
|
||||
origin: UserPermission
|
||||
current: UserPermission
|
||||
|
||||
|
||||
class MemberPermissionChangeEvent(MemberStateChangeEvent):
|
||||
"""成员权限改变的事件(该成员不是Bot)"""
|
||||
origin: UserPermission
|
||||
current: UserPermission
|
@ -0,0 +1,170 @@
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from pydantic import Field
|
||||
from typing_extensions import Literal
|
||||
|
||||
from .base import Event
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..bot import Bot
|
||||
|
||||
|
||||
class RequestEvent(Event):
|
||||
"""请求事件基类"""
|
||||
event_id: int = Field(alias='eventId')
|
||||
message: str
|
||||
nick: str
|
||||
|
||||
|
||||
class NewFriendRequestEvent(RequestEvent):
|
||||
"""添加好友申请"""
|
||||
from_id: int = Field(alias='fromId')
|
||||
group_id: int = Field(0, alias='groupId')
|
||||
|
||||
async def approve(self, bot: "Bot"):
|
||||
"""
|
||||
:说明:
|
||||
|
||||
通过此人的好友申请
|
||||
|
||||
:参数:
|
||||
|
||||
* ``bot: Bot``: 当前的 ``Bot`` 对象
|
||||
"""
|
||||
return await bot.api.post('/resp/newFriendRequestEvent',
|
||||
params={
|
||||
'eventId': self.event_id,
|
||||
'groupId': self.group_id,
|
||||
'fromId': self.from_id,
|
||||
'operate': 0
|
||||
})
|
||||
|
||||
async def reject(self,
|
||||
bot: "Bot",
|
||||
operate: Literal[1, 2] = 1,
|
||||
message: str = ''):
|
||||
"""
|
||||
:说明:
|
||||
|
||||
拒绝此人的好友申请
|
||||
|
||||
:参数:
|
||||
|
||||
* ``bot: Bot``: 当前的 ``Bot`` 对象
|
||||
* ``operate: Literal[1, 2]``: 响应的操作类型
|
||||
|
||||
* ``1``: 拒绝添加好友
|
||||
* ``2``: 拒绝添加好友并添加黑名单,不再接收该用户的好友申请
|
||||
|
||||
* ``message: str``: 回复的信息
|
||||
"""
|
||||
assert operate > 0
|
||||
return await bot.api.post('/resp/newFriendRequestEvent',
|
||||
params={
|
||||
'eventId': self.event_id,
|
||||
'groupId': self.group_id,
|
||||
'fromId': self.from_id,
|
||||
'operate': operate,
|
||||
'message': message
|
||||
})
|
||||
|
||||
|
||||
class MemberJoinRequestEvent(RequestEvent):
|
||||
"""用户入群申请(Bot需要有管理员权限)"""
|
||||
from_id: int = Field(alias='fromId')
|
||||
group_id: int = Field(alias='groupId')
|
||||
group_name: str = Field(alias='groupName')
|
||||
|
||||
async def approve(self, bot: "Bot"):
|
||||
"""
|
||||
:说明:
|
||||
|
||||
通过此人的加群申请
|
||||
|
||||
:参数:
|
||||
|
||||
* ``bot: Bot``: 当前的 ``Bot`` 对象
|
||||
"""
|
||||
return await bot.api.post('/resp/memberJoinRequestEvent',
|
||||
params={
|
||||
'eventId': self.event_id,
|
||||
'groupId': self.group_id,
|
||||
'fromId': self.from_id,
|
||||
'operate': 0
|
||||
})
|
||||
|
||||
async def reject(self,
|
||||
bot: "Bot",
|
||||
operate: Literal[1, 2, 3, 4] = 1,
|
||||
message: str = ''):
|
||||
"""
|
||||
:说明:
|
||||
|
||||
拒绝(忽略)此人的加群申请
|
||||
|
||||
:参数:
|
||||
|
||||
* ``bot: Bot``: 当前的 ``Bot`` 对象
|
||||
* ``operate: Literal[1, 2, 3, 4]``: 响应的操作类型
|
||||
|
||||
* ``1``: 拒绝入群
|
||||
* ``2``: 忽略请求
|
||||
* ``3``: 拒绝入群并添加黑名单,不再接收该用户的入群申请
|
||||
* ``4``: 忽略入群并添加黑名单,不再接收该用户的入群申请
|
||||
|
||||
* ``message: str``: 回复的信息
|
||||
"""
|
||||
assert operate > 0
|
||||
return await bot.api.post('/resp/memberJoinRequestEvent',
|
||||
params={
|
||||
'eventId': self.event_id,
|
||||
'groupId': self.group_id,
|
||||
'fromId': self.from_id,
|
||||
'operate': operate,
|
||||
'message': message
|
||||
})
|
||||
|
||||
|
||||
class BotInvitedJoinGroupRequestEvent(RequestEvent):
|
||||
"""Bot被邀请入群申请"""
|
||||
from_id: int = Field(alias='fromId')
|
||||
group_id: int = Field(alias='groupId')
|
||||
group_name: str = Field(alias='groupName')
|
||||
|
||||
async def approve(self, bot: "Bot"):
|
||||
"""
|
||||
:说明:
|
||||
|
||||
通过这份被邀请入群申请
|
||||
|
||||
:参数:
|
||||
|
||||
* ``bot: Bot``: 当前的 ``Bot`` 对象
|
||||
"""
|
||||
return await bot.api.post('/resp/botInvitedJoinGroupRequestEvent',
|
||||
params={
|
||||
'eventId': self.event_id,
|
||||
'groupId': self.group_id,
|
||||
'fromId': self.from_id,
|
||||
'operate': 0
|
||||
})
|
||||
|
||||
async def reject(self, bot: "Bot", message: str = ""):
|
||||
"""
|
||||
:说明:
|
||||
|
||||
拒绝这份被邀请入群申请
|
||||
|
||||
:参数:
|
||||
|
||||
* ``bot: Bot``: 当前的 ``Bot`` 对象
|
||||
* ``message: str``: 邀请消息
|
||||
"""
|
||||
return await bot.api.post('/resp/botInvitedJoinGroupRequestEvent',
|
||||
params={
|
||||
'eventId': self.event_id,
|
||||
'groupId': self.group_id,
|
||||
'fromId': self.from_id,
|
||||
'operate': 1,
|
||||
'message': message
|
||||
})
|
Reference in New Issue
Block a user