Skip to content

Commit

Permalink
✨ [Feature] on_message_audit 主动消息审核事件
Browse files Browse the repository at this point in the history
  • Loading branch information
foxwhite25 committed Jan 23, 2022
1 parent bd4b75e commit 3e2ad7e
Show file tree
Hide file tree
Showing 8 changed files with 128 additions and 26 deletions.
31 changes: 24 additions & 7 deletions docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -209,27 +209,27 @@ AutoShardedClient
:param audio: 音频资料。
:type message: :class:`AudioAction`

.. function:: on_audio_start(audio)
.. function:: on_audio_stop(audio)

音频开始播放时调用
音频停止播放时调用

这需要启用 :attr:`Intents.audio`。

:param audio: 音频资料。
:type message: :class:`AudioAction`

.. function:: on_audio_start(audio)
.. function:: on_mic_start(audio)

音频开始播放时调用
有人上麦时时调用

这需要启用 :attr:`Intents.audio`。

:param audio: 音频资料。
:type message: :class:`AudioAction`

.. function:: on_audio_start(audio)
.. function:: on_mic_stop(audio)

音频开始播放时调用
有人下麦时时调用

这需要启用 :attr:`Intents.audio`。

Expand All @@ -246,11 +246,20 @@ AutoShardedClient

你的机器人自己的消息通过此事件发送。
这可能会导致“递归”的情况,具体取决于你的机器人的编程方式。
如果你希望机器人不回复自己,请考虑检查用户 ID。注意:class:`~ext.commands.Bot` 没有这个问题。
如果你希望机器人不回复自己,请考虑检查用户 ID。注意 :class:`~ext.commands.Bot` 没有这个问题。

:param message: 当前消息。
:type message: :class:`Message`

.. function:: on_message_audit(audit)

在消息审核通过或拒绝时调用。

这需要启用 :attr:`Intents.audit`。

:param audit: 当前消息审核。
:type message: :class:`MessageAudit`

.. function:: on_guild_channel_delete(channel)
on_guild_channel_create(channel)

Expand Down Expand Up @@ -686,6 +695,14 @@ Message

.. attributetable:: Message

.. autoclass:: Message()
:members:

MessageAudit
~~~~~~~

.. attributetable:: MessageAudit

.. autoclass:: Message()
:members:

Expand Down
10 changes: 9 additions & 1 deletion examples/basic_bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,15 @@ async def roll(ctx, dice: str):
@bot.command(description='当你有选择困难症') # 注册指令 '?choose', 参数为多个choices, 例如 ?choose a b,choose会是['a', 'b']
async def choose(ctx, *choices: str):
"""在多个选项之间进行选择。"""
await ctx.reply(random.choice(choices)) # 发送从 List 中随机选择一个
audit_id = await ctx.reply(random.choice(choices)) # 发送从 List 中随机选择一个,

# 因为用的是 send,而也没有附上 referece,所以是主动消息,因此返回的是 str 的 audit_id

def audit_message(audit: qq.MessageAudit): # 检测 audit 事件的 id 是否和获得的 id 一致
return audit.id == audit_id

audit = await bot.wait_for('message_audit', check=audit_message, timeout=60) # 等待 message_audit 事件
await ctx.reply("Audit passed" if audit.passed else "Audit failed")


@bot.command() # 注册指令 '?repeat', 参数为 time content, content 默认值为 重复...
Expand Down
13 changes: 7 additions & 6 deletions qq/abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
from .channel import CategoryChannel, TextChannel, PartialMessageable, DMChannel
from .guild import Guild
from .state import ConnectionState
from .message import Message, MessageReference, PartialMessage
from .message import Message, MessageReference, PartialMessage, MessageAudit
from .types.channel import (
Channel as ChannelPayload,
)
Expand Down Expand Up @@ -114,7 +114,7 @@ async def send(
reference: Union[Message, MessageReference, PartialMessage] = ...,
mention_author: Member = ...,
direct=...,
) -> Message:
) -> Union[Message, str]:
...

async def send(
Expand All @@ -131,7 +131,8 @@ async def send(
"""|coro|
使用给定的内容向目的地发送消息。
content 必须是可以通过 ``str(content)`` 转换为字符串的类型。
如果是主动信息,不一定会有返回。
如果不填入 ``reference`` 将会被腾讯视为主动消息。
如果是主动信息,输出将会是 ``audit_id``。
Parameters
------------
Expand Down Expand Up @@ -162,7 +163,7 @@ async def send(
Returns
---------
:class:`~qq.Message`
Union[:class:`~qq.Message`, :class:`~qq.MessageAudit`]
发送的消息。
"""

Expand Down Expand Up @@ -190,8 +191,8 @@ async def send(
direct=direct
)

if 'audit_id' in data:
return None
if reference is None:
return data['data']['message_audit']['audit_id']

ret = state.create_message(channel=channel, data=data, direct=direct)
if delete_after is not None:
Expand Down
7 changes: 1 addition & 6 deletions qq/channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -923,7 +923,7 @@ class DMChannel(abc.Messageable, Hashable):
垃圾资讯,无视即可,官方不知道在搞什么jb东西
"""

__slots__ = ('id', 'recipient', 'me', 'channel_id', '_state', '_created_time')
__slots__ = ('id', 'recipient', 'me', 'channel_id', '_state')

def __init__(self, *, me: ClientUser, state: ConnectionState, data: DMChannelPayload, recipients: User):
self._state: ConnectionState = state
Expand Down Expand Up @@ -959,11 +959,6 @@ def type(self) -> ChannelType:
""":class:`ChannelType`: 频道的 QQ 类型。"""
return ChannelType.private

@property
def created_at(self) -> datetime.datetime:
""":class:`datetime.datetime`: 以 UTC 格式返回直接消息通道的创建时间。"""
return utils.parse_time(self._created_time)

def get_partial_message(self, message_id: int, /) -> PartialMessage:
"""从消息 ID 创建一个 :class:`PartialMessage` 。
如果您想处理消息并且只拥有其 ID 而不进行不必要的 API 调用,这将非常有用。
Expand Down
2 changes: 1 addition & 1 deletion qq/ext/commands/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ def valid(self) -> bool:
return self.prefix is not None and self.command is not None

async def _get_channel(self) -> Tuple[qq.abc.Messageable, bool]:
return self.guild if self.message.direct else self.channel, True
return self.guild if self.message.direct else self.channel, self.message.direct

@property
def clean_prefix(self) -> str:
Expand Down
3 changes: 1 addition & 2 deletions qq/flags.py
Original file line number Diff line number Diff line change
Expand Up @@ -312,8 +312,7 @@ def audit(self):
这对应于以下事件:
- :func:`on_audit_pass`
- :func:`on_audit_reject`
- :func:`on_message-audit`
"""
return 1 << 27

Expand Down
80 changes: 79 additions & 1 deletion qq/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,89 @@
'Message',
'PartialMessage',
'MessageReference',
'MessageAudit'
)


class MessageAudit:
"""表示审核结果。"""
"""表示消息审核情况。
.. container:: operations
.. describe:: x == y
检查两个审核是否相等。
.. describe:: x != y
检查两个审核是否不相等。
Attributes
-----------
id: :class:`str`
审核的 ID 。
message_id: Optional[:class:`str`]
消息 ID,只有审核通过事件才会有值。
audit_time: :class:`datetime.datetime`
消息审核时间
create_time: :class:`datetime.datetime`
消息创建时间
channel_id: :class:`int`
审核消息的子频道 ID
guild_id: :class:`str`
审核消息的频道 ID
"""

__slots__ = (
'_state',
'id',
'message_id',
'guild_id',
'channel_id',
'audit_time',
'create_time',
'_audit_state'
)

def __init__(self, state: ConnectionState, data: MessageAuditPayload, audit_state):
self.id: str = data['audit_id']
self._state = state
self.message_id: Optional[str] = data.get('message_id')
self.channel_id: int = int(data['channel_id'])
self.guild_id: int = int(data['guild_id'])
self.audit_time: Optional[datetime.datetime] = utils.parse_time(data.get('audit_time'))
self.create_time: datetime.datetime = utils.parse_time(data['create_time'])
self._audit_state = audit_state

def __repr__(self) -> str:
name = self.__class__.__name__
return (
f'<{name} id={self.id}>'
)

def __eq__(self, other: Any) -> bool:
return isinstance(other, MessageAudit) and self.id == other.id

def __ne__(self, other: Any) -> bool:
return isinstance(other, MessageAudit) and self.id != other.id

@property
def passed(self):
""":class:`bool`: 返回消息是否通过审核
"""
return True is self._audit_state is True

@property
def rejected(self):
""":class:`bool`: 返回消息是否没通过审核
"""
return True is self._audit_state is False

@property
def pending(self):
""":class:`bool`: 返回消息是否正在审核
"""
return True is self._audit_state is None


class DeletedReferencedMessage:
Expand Down
8 changes: 6 additions & 2 deletions qq/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
from .raw_models import RawReactionActionEvent, RawReactionClearEvent, RawReactionClearEmojiEvent
from .user import User, ClientUser
from .guild import Guild
from .message import Message
from .message import Message, MessageAudit
from .member import Member

if TYPE_CHECKING:
Expand Down Expand Up @@ -305,6 +305,7 @@ def _get_guild_channel(self, data: MessagePayload) -> Tuple[Union[Channel], Opti
channel = guild and guild._resolve_channel(channel_id)
else:
channel = DMChannel._from_message(state=self, channel_id=channel_id, guild_id=int(data['guild_id']))
self._add_private_channel(channel)
guild = None
return channel or PartialMessageable(state=self, id=channel_id), guild

Expand Down Expand Up @@ -481,7 +482,10 @@ def parse_direct_message_create(self, data) -> None:
self.parse_at_message_create(data)

def parse_message_audit_pass(self, data) -> None:
self.dispatch('audit_pass', data)
self.dispatch('message_audit', MessageAudit(state=self, data=data, audit_state=True))

def parse_message_audit_reject(self, data) -> None:
self.dispatch('message_audit', MessageAudit(state=self, data=data, audit_state=False))

def parse_channel_delete(self, data) -> None:
guild = self._get_guild(data.get('guild_id'))
Expand Down

0 comments on commit 3e2ad7e

Please sign in to comment.