Skip to content

Commit

Permalink
Split bulk message delete and message delete into separate events
Browse files Browse the repository at this point in the history
  • Loading branch information
davfsa committed Nov 9, 2021
1 parent ad92c70 commit 7965fcf
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 103 deletions.
2 changes: 2 additions & 0 deletions changes/897.breaking.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Split bulk message delete from normal delete
- The new event is now `hikari.events.message_events.GuildBulkMessageDeleteEvent`
1 change: 1 addition & 0 deletions changes/897.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add `old_message` attribute to `hikari.events.message_events.MessageDelete`
32 changes: 20 additions & 12 deletions hikari/api/event_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
from hikari import invites as invite_models
from hikari import messages as messages_models
from hikari import presences as presences_models
from hikari import snowflakes
from hikari import users as user_models
from hikari import voices as voices_models
from hikari.api import shard as gateway_shard
Expand Down Expand Up @@ -752,7 +753,11 @@ def deserialize_message_update_event(

@abc.abstractmethod
def deserialize_message_delete_event(
self, shard: gateway_shard.GatewayShard, payload: data_binding.JSONObject
self,
shard: gateway_shard.GatewayShard,
payload: data_binding.JSONObject,
*,
old_message: typing.Optional[messages_models.Message],
) -> message_events.MessageDeleteEvent:
"""Parse a raw payload from Discord into a message delete event object.
Expand All @@ -762,6 +767,8 @@ def deserialize_message_delete_event(
The shard that emitted this event.
payload : hikari.internal.data_binding.JSONObject
The dict payload to parse.
old_message : typing.Optional[hikari.messages.Message]
The old message object.
Returns
-------
Expand All @@ -770,27 +777,28 @@ def deserialize_message_delete_event(
"""

@abc.abstractmethod
def deserialize_message_delete_bulk_event(
self, shard: gateway_shard.GatewayShard, payload: data_binding.JSONObject
) -> message_events.MessageDeleteEvent:
"""Parse a raw payload from Discord into a message delete bulk event object.
def deserialize_guild_message_delete_bulk_event(
self,
shard: gateway_shard.GatewayShard,
payload: data_binding.JSONObject,
*,
old_messages: typing.Mapping[snowflakes.Snowflake, messages_models.Message],
) -> message_events.GuildBulkMessageDeleteEvent:
"""Parse a raw payload from Discord into a guild message delete bulk event object.
Parameters
----------
shard : hikari.api.shard.GatewayShard
The shard that emitted this event.
payload : hikari.internal.data_binding.JSONObject
The dict payload to parse.
old_messages : typing.Mapping[hikari.snowflakes.Snowflake, hikari.messages.Message]
A mapping of the old message objects.
Returns
-------
hikari.events.message_events.MessageDeleteEvent
The parsed message delete bulk event object.
Raises
------
builtins.NotImplementedError
If a bulk delete occurs in a DM channel.
hikari.events.message_events.GuildBulkMessageDeleteEvent
The parsed guild message delete bulk event object.
"""

###################
Expand Down
145 changes: 84 additions & 61 deletions hikari/events/message_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"GuildMessageCreateEvent",
"GuildMessageUpdateEvent",
"GuildMessageDeleteEvent",
"GuildBulkMessageDeleteEvent",
"DMMessageCreateEvent",
"DMMessageUpdateEvent",
"DMMessageDeleteEvent",
Expand Down Expand Up @@ -594,73 +595,38 @@ class DMMessageUpdateEvent(MessageUpdateEvent):

@base_events.requires_intents(intents.Intents.GUILD_MESSAGES, intents.Intents.DM_MESSAGES)
class MessageDeleteEvent(MessageEvent, abc.ABC):
"""Special event that is triggered when one or more messages get deleted.
"""Special event that is triggered when a message gets deleted.
!!! note
Due to Discord limitations, most message information is unavailable
during deletion events.
You can check if the message was in a singular deletion by checking the
`is_bulk` attribute.
"""

__slots__: typing.Sequence[str] = ()

@property
def message_id(self) -> snowflakes.Snowflake:
"""Get the ID of the first deleted message.
This is contextually useful if you know this is not a bulk deletion
event. For all other purposes, this is the same as running
`next(iter(event.message_ids))`.
Returns
-------
hikari.snowflakes.Snowflake
The first deleted message ID.
"""
try:
return next(iter(self.message_ids))
except StopIteration:
raise RuntimeError("No messages were sent in a bulk delete! Please shout at Discord to fix this!") from None

@property
@abc.abstractmethod
def message_ids(self) -> typing.AbstractSet[snowflakes.Snowflake]:
"""Set of message IDs that were bulk deleted.
Returns
-------
typing.AbstractSet[hikari.snowflakes.Snowflake]
A sequence of message IDs that were bulk deleted.
"""
def message_id(self) -> snowflakes.Snowflake:
"""The ID of the message that was deleted."""

@property
@abc.abstractmethod
def is_bulk(self) -> bool:
"""Flag that determines whether this was a bulk deletion or not.
def old_message(self) -> typing.Optional[messages.Message]:
"""The object of the message that was deleted.
Returns
-------
builtins.bool
`builtins.True` if this was a bulk deletion, or `builtins.False`
if it was a regular message deletion.
Will be `None` if the message was not found in the cache.
"""


@attr_extensions.with_copy
@attr.define(kw_only=True, weakref_slot=False)
@base_events.requires_intents(intents.Intents.GUILD_MESSAGES)
class GuildMessageDeleteEvent(MessageDeleteEvent):
"""Event that is triggered if messages are deleted in a guild.
"""Event that is triggered if a message is deleted in a guild.
!!! note
Due to Discord limitations, most message information is unavailable
during deletion events.
This is triggered for singular message deletion, and bulk message
deletion. You can check if the message was in a singular deletion by
checking the `is_bulk` attribute.
"""

app: traits.RESTAware = attr.field(metadata={attr_extensions.SKIP_DEEP_COPY: True})
Expand All @@ -670,25 +636,19 @@ class GuildMessageDeleteEvent(MessageDeleteEvent):
# <<inherited docstring from MessageEvent>>

guild_id: snowflakes.Snowflake = attr.field()
"""ID of the guild that this event occurred in.
"""ID of the guild that this event occurred in."""

Returns
-------
hikari.snowflakes.Snowflake
The ID of the guild.
"""

is_bulk: bool = attr.field()
message_id: snowflakes.Snowflake = attr.field()
# <<inherited docstring from MessageDeleteEvent>>

message_ids: typing.AbstractSet[snowflakes.Snowflake] = attr.field()
old_message: snowflakes.Snowflake = attr.field()
# <<inherited docstring from MessageDeleteEvent>>

shard: shard_.GatewayShard = attr.field(metadata={attr_extensions.SKIP_DEEP_COPY: True})
# <<inherited docstring from ShardEvent>>

def get_channel(self) -> typing.Optional[channels.TextableGuildChannel]:
"""Get the cached channel the messages were sent in, if known.
"""Get the cached channel the message were sent in, if known.
Returns
-------
Expand Down Expand Up @@ -728,17 +688,11 @@ def get_guild(self) -> typing.Optional[guilds.GatewayGuild]:
@attr.define(kw_only=True, weakref_slot=False)
@base_events.requires_intents(intents.Intents.DM_MESSAGES)
class DMMessageDeleteEvent(MessageDeleteEvent):
"""Event that is triggered if messages are deleted in a DM.
"""Event that is triggered if a message is deleted in a DM.
!!! note
Due to Discord limitations, most message information is unavailable
during deletion events.
This is triggered for singular message deletion, and bulk message
deletion, although the latter is not expected to occur in DMs.
You can check if the message was in a singular deletion by checking the
`is_bulk` attribute.
"""

app: traits.RESTAware = attr.field(metadata={attr_extensions.SKIP_DEEP_COPY: True})
Expand All @@ -747,11 +701,80 @@ class DMMessageDeleteEvent(MessageDeleteEvent):
channel_id: snowflakes.Snowflake = attr.field()
# <<inherited docstring from MessageEvent>>

is_bulk: bool = attr.field()
message_id: snowflakes.Snowflake = attr.field()
# <<inherited docstring from MessageDeleteEvent>>

message_ids: typing.AbstractSet[snowflakes.Snowflake] = attr.field()
old_message: snowflakes.Snowflake = attr.field()
# <<inherited docstring from MessageDeleteEvent>>

shard: shard_.GatewayShard = attr.field(metadata={attr_extensions.SKIP_DEEP_COPY: True})
# <<inherited docstring from ShardEvent>>


@attr_extensions.with_copy
@attr.define(kw_only=True, weakref_slot=False)
@base_events.requires_intents(intents.Intents.GUILD_MESSAGES)
class GuildBulkMessageDeleteEvent(shard_events.ShardEvent):
"""Event that is triggered when a bulk deletion is triggered in a guild.
!!! note
Due to Discord limitations, most message information is unavailable
during deletion events.
"""

app: traits.RESTAware = attr.field(metadata={attr_extensions.SKIP_DEEP_COPY: True})
# <<inherited docstring from Event>>

channel_id: snowflakes.Snowflake = attr.field()
"""ID of the channel that this event concerns."""

guild_id: snowflakes.Snowflake = attr.field()
"""ID of the guild that this event occurred in."""

message_ids: typing.AbstractSet[snowflakes.Snowflake] = attr.field()
"""Set of message IDs that were bulk deleted."""

old_messages: typing.Mapping[snowflakes.Snowflake, messages.Message] = attr.field()
"""Mapping of a snowflake to the deleted message object.
If the message was not found in the cache it will be missing from the mapping.
"""

shard: shard_.GatewayShard = attr.field(metadata={attr_extensions.SKIP_DEEP_COPY: True})
# <<inherited docstring from ShardEvent>>

def get_channel(self) -> typing.Optional[channels.TextableGuildChannel]:
"""Get the cached channel the messages were sent in, if known.
Returns
-------
typing.Optional[hikari.channels.TextableGuildChannel]
The channel the messages were sent in, or `builtins.None` if not
known/cached.
"""
if not isinstance(self.app, traits.CacheAware):
return None

channel = self.app.cache.get_guild_channel(self.channel_id)
assert channel is None or isinstance(
channel, channels.TextableGuildChannel
), f"Cached channel ID is not a TextableGuildChannel, but a {type(channel).__name__}!"
return channel

def get_guild(self) -> typing.Optional[guilds.GatewayGuild]:
"""Get the cached guild this event corresponds to, if known.
!!! note
You will need `hikari.intents.Intents.GUILDS` enabled to receive this
information.
Returns
-------
hikari.guilds.GatewayGuild
The gateway guild that this event corresponds to, if known and
cached.
"""
if not isinstance(self.app, traits.CacheAware):
return None

return self.app.cache.get_guild(self.guild_id)
50 changes: 24 additions & 26 deletions hikari/impl/event_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,7 @@ def deserialize_message_create_event(

return message_events.GuildMessageCreateEvent(shard=shard, message=message)

def deserialize_message_update_event( # noqa: CFQ001
def deserialize_message_update_event(
self,
shard: gateway_shard.GatewayShard,
payload: data_binding.JSONObject,
Expand All @@ -495,48 +495,46 @@ def deserialize_message_update_event( # noqa: CFQ001
return message_events.GuildMessageUpdateEvent(shard=shard, message=message, old_message=old_message)

def deserialize_message_delete_event(
self, shard: gateway_shard.GatewayShard, payload: data_binding.JSONObject
self,
shard: gateway_shard.GatewayShard,
payload: data_binding.JSONObject,
*,
old_message: typing.Optional[messages_models.Message],
) -> message_events.MessageDeleteEvent:
channel_id = snowflakes.Snowflake(payload["channel_id"])
message_ids = collections.SnowflakeSet(int(payload["id"]))
message_id = snowflakes.Snowflake(payload["id"])

if "guild_id" in payload:
return message_events.GuildMessageDeleteEvent(
app=self._app,
shard=shard,
channel_id=channel_id,
message_ids=message_ids,
is_bulk=False,
message_id=message_id,
guild_id=snowflakes.Snowflake(payload["guild_id"]),
old_message=old_message,
)

return message_events.DMMessageDeleteEvent(
app=self._app,
shard=shard,
channel_id=channel_id,
message_ids=message_ids,
is_bulk=False,
message_id=message_id,
old_message=old_message,
)

def deserialize_message_delete_bulk_event(
self, shard: gateway_shard.GatewayShard, payload: data_binding.JSONObject
) -> message_events.MessageDeleteEvent:

message_ids = collections.SnowflakeSet(*(snowflakes.Snowflake(message_id) for message_id in payload["ids"]))
channel_id = snowflakes.Snowflake(payload["channel_id"])

if "guild_id" in payload:
return message_events.GuildMessageDeleteEvent(
app=self._app,
shard=shard,
channel_id=channel_id,
guild_id=snowflakes.Snowflake(payload["guild_id"]),
message_ids=message_ids,
is_bulk=True,
)

return message_events.DMMessageDeleteEvent(
app=self._app, shard=shard, channel_id=channel_id, message_ids=message_ids, is_bulk=True
def deserialize_guild_message_delete_bulk_event(
self,
shard: gateway_shard.GatewayShard,
payload: data_binding.JSONObject,
old_messages: typing.Mapping[snowflakes.Snowflake, messages_models.Message],
) -> message_events.GuildBulkMessageDeleteEvent:
return message_events.GuildBulkMessageDeleteEvent(
app=self._app,
shard=shard,
channel_id=snowflakes.Snowflake(payload["channel_id"]),
guild_id=snowflakes.Snowflake(payload["guild_id"]),
message_ids=collections.SnowflakeSet(*(snowflakes.Snowflake(message_id) for message_id in payload["ids"])),
old_messages=old_messages,
)

###################
Expand Down
Loading

0 comments on commit 7965fcf

Please sign in to comment.