mirror of
https://github.com/Rapptz/discord.py.git
synced 2025-07-09 11:31:58 +00:00
Add PartialMessage to allow working with channel/message_id pairs.
Fix #5905
This commit is contained in:
parent
bde5bb5d5c
commit
3fe6d261f1
@ -517,6 +517,28 @@ class TextChannel(discord.abc.Messageable, discord.abc.GuildChannel, Hashable):
|
|||||||
data = await self._state.http.follow_webhook(self.id, webhook_channel_id=destination.id, reason=reason)
|
data = await self._state.http.follow_webhook(self.id, webhook_channel_id=destination.id, reason=reason)
|
||||||
return Webhook._as_follower(data, channel=destination, user=self._state.user)
|
return Webhook._as_follower(data, channel=destination, user=self._state.user)
|
||||||
|
|
||||||
|
def get_partial_message(self, message_id):
|
||||||
|
"""Creates a :class:`PartialMessage` from the message ID.
|
||||||
|
|
||||||
|
This is useful if you want to work with a message and only have its ID without
|
||||||
|
doing an unnecessary API call.
|
||||||
|
|
||||||
|
.. versionadded:: 1.6
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
------------
|
||||||
|
message_id: :class:`int`
|
||||||
|
The message ID to create a partial message for.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
---------
|
||||||
|
:class:`PartialMessage`
|
||||||
|
The partial message.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from .message import PartialMessage
|
||||||
|
return PartialMessage(channel=self, id=message_id)
|
||||||
|
|
||||||
class VoiceChannel(discord.abc.Connectable, discord.abc.GuildChannel, Hashable):
|
class VoiceChannel(discord.abc.Connectable, discord.abc.GuildChannel, Hashable):
|
||||||
"""Represents a Discord guild voice channel.
|
"""Represents a Discord guild voice channel.
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ from .reaction import Reaction
|
|||||||
from .emoji import Emoji
|
from .emoji import Emoji
|
||||||
from .partial_emoji import PartialEmoji
|
from .partial_emoji import PartialEmoji
|
||||||
from .calls import CallMessage
|
from .calls import CallMessage
|
||||||
from .enums import MessageType, try_enum
|
from .enums import MessageType, ChannelType, try_enum
|
||||||
from .errors import InvalidArgument, ClientException, HTTPException
|
from .errors import InvalidArgument, ClientException, HTTPException
|
||||||
from .embeds import Embed
|
from .embeds import Embed
|
||||||
from .member import Member
|
from .member import Member
|
||||||
@ -48,10 +48,26 @@ from .sticker import Sticker
|
|||||||
__all__ = (
|
__all__ = (
|
||||||
'Attachment',
|
'Attachment',
|
||||||
'Message',
|
'Message',
|
||||||
|
'PartialMessage',
|
||||||
'MessageReference',
|
'MessageReference',
|
||||||
'DeletedReferencedMessage',
|
'DeletedReferencedMessage',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def convert_emoji_reaction(emoji):
|
||||||
|
if isinstance(emoji, Reaction):
|
||||||
|
emoji = emoji.emoji
|
||||||
|
|
||||||
|
if isinstance(emoji, Emoji):
|
||||||
|
return '%s:%s' % (emoji.name, emoji.id)
|
||||||
|
if isinstance(emoji, PartialEmoji):
|
||||||
|
return emoji._as_reaction()
|
||||||
|
if isinstance(emoji, str):
|
||||||
|
# Reactions can be in :name:id format, but not <:name:id>.
|
||||||
|
# No existing emojis have <> in them, so this should be okay.
|
||||||
|
return emoji.strip('<>')
|
||||||
|
|
||||||
|
raise InvalidArgument('emoji argument must be str, Emoji, or Reaction not {.__class__.__name__}.'.format(emoji))
|
||||||
|
|
||||||
class Attachment:
|
class Attachment:
|
||||||
"""Represents an attachment from Discord.
|
"""Represents an attachment from Discord.
|
||||||
|
|
||||||
@ -1117,7 +1133,7 @@ class Message(Hashable):
|
|||||||
The emoji parameter is invalid.
|
The emoji parameter is invalid.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
emoji = self._emoji_reaction(emoji)
|
emoji = convert_emoji_reaction(emoji)
|
||||||
await self._state.http.add_reaction(self.channel.id, self.id, emoji)
|
await self._state.http.add_reaction(self.channel.id, self.id, emoji)
|
||||||
|
|
||||||
async def remove_reaction(self, emoji, member):
|
async def remove_reaction(self, emoji, member):
|
||||||
@ -1152,7 +1168,7 @@ class Message(Hashable):
|
|||||||
The emoji parameter is invalid.
|
The emoji parameter is invalid.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
emoji = self._emoji_reaction(emoji)
|
emoji = convert_emoji_reaction(emoji)
|
||||||
|
|
||||||
if member.id == self._state.self_id:
|
if member.id == self._state.self_id:
|
||||||
await self._state.http.remove_own_reaction(self.channel.id, self.id, emoji)
|
await self._state.http.remove_own_reaction(self.channel.id, self.id, emoji)
|
||||||
@ -1187,25 +1203,9 @@ class Message(Hashable):
|
|||||||
The emoji parameter is invalid.
|
The emoji parameter is invalid.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
emoji = self._emoji_reaction(emoji)
|
emoji = convert_emoji_reaction(emoji)
|
||||||
await self._state.http.clear_single_reaction(self.channel.id, self.id, emoji)
|
await self._state.http.clear_single_reaction(self.channel.id, self.id, emoji)
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _emoji_reaction(emoji):
|
|
||||||
if isinstance(emoji, Reaction):
|
|
||||||
emoji = emoji.emoji
|
|
||||||
|
|
||||||
if isinstance(emoji, Emoji):
|
|
||||||
return '%s:%s' % (emoji.name, emoji.id)
|
|
||||||
if isinstance(emoji, PartialEmoji):
|
|
||||||
return emoji._as_reaction()
|
|
||||||
if isinstance(emoji, str):
|
|
||||||
# Reactions can be in :name:id format, but not <:name:id>.
|
|
||||||
# No existing emojis have <> in them, so this should be okay.
|
|
||||||
return emoji.strip('<>')
|
|
||||||
|
|
||||||
raise InvalidArgument('emoji argument must be str, Emoji, or Reaction not {.__class__.__name__}.'.format(emoji))
|
|
||||||
|
|
||||||
async def clear_reactions(self):
|
async def clear_reactions(self):
|
||||||
"""|coro|
|
"""|coro|
|
||||||
|
|
||||||
@ -1291,3 +1291,101 @@ class Message(Hashable):
|
|||||||
data['guild_id'] = self.guild.id
|
data['guild_id'] = self.guild.id
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
def implement_partial_methods(cls):
|
||||||
|
msg = Message
|
||||||
|
for name in cls._exported_names:
|
||||||
|
func = getattr(msg, name)
|
||||||
|
setattr(cls, name, func)
|
||||||
|
return cls
|
||||||
|
|
||||||
|
@implement_partial_methods
|
||||||
|
class PartialMessage(Hashable):
|
||||||
|
"""Represents a partial message to aid with working messages when only
|
||||||
|
a message and channel ID are present.
|
||||||
|
|
||||||
|
There are two ways to construct this class. The first one is through
|
||||||
|
the constructor itself, and the second is via
|
||||||
|
:meth:`TextChannel.get_partial_message`.
|
||||||
|
|
||||||
|
Note that this class is trimmed down and has no rich attributes.
|
||||||
|
|
||||||
|
.. versionadded:: 1.6
|
||||||
|
|
||||||
|
Attributes
|
||||||
|
-----------
|
||||||
|
channel: :class:`TextChannel`
|
||||||
|
The text channel associated with this partial message.
|
||||||
|
id: :class:`int`
|
||||||
|
The message ID.
|
||||||
|
"""
|
||||||
|
|
||||||
|
__slots__ = ('channel', 'id', '_state')
|
||||||
|
|
||||||
|
_exported_names = (
|
||||||
|
'jump_url',
|
||||||
|
'delete',
|
||||||
|
'edit',
|
||||||
|
'publish',
|
||||||
|
'pin',
|
||||||
|
'unpin',
|
||||||
|
'add_reaction',
|
||||||
|
'remove_reaction',
|
||||||
|
'clear_reaction',
|
||||||
|
'clear_reactions',
|
||||||
|
'reply',
|
||||||
|
'to_reference',
|
||||||
|
)
|
||||||
|
|
||||||
|
def __init__(self, *, channel, id):
|
||||||
|
if channel.type not in (ChannelType.text, ChannelType.news):
|
||||||
|
raise TypeError('Expected TextChannel not %r' % type(channel))
|
||||||
|
|
||||||
|
self.channel = channel
|
||||||
|
self._state = channel._state
|
||||||
|
self.id = id
|
||||||
|
|
||||||
|
def _update(self, data):
|
||||||
|
# This is used for duck typing purposes.
|
||||||
|
# Just do nothing with the data.
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Also needed for duck typing purposes
|
||||||
|
# n.b. not exposed
|
||||||
|
pinned = property(None, lambda x, y: ...)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return '<PartialMessage id={0.id} channel={0.channel!r}>'.format(self)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def created_at(self):
|
||||||
|
""":class:`datetime.datetime`: The partial message's creation time in UTC."""
|
||||||
|
return utils.snowflake_time(self.id)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def guild(self):
|
||||||
|
""":class:`Guild`: The guild that the partial message belongs to."""
|
||||||
|
return self.channel.guild
|
||||||
|
|
||||||
|
async def fetch(self):
|
||||||
|
"""|coro|
|
||||||
|
|
||||||
|
Fetches the partial message to a full :class:`Message`.
|
||||||
|
|
||||||
|
Raises
|
||||||
|
--------
|
||||||
|
NotFound
|
||||||
|
The message was not found.
|
||||||
|
Forbidden
|
||||||
|
You do not have the permissions required to get a message.
|
||||||
|
HTTPException
|
||||||
|
Retrieving the message failed.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
--------
|
||||||
|
:class:`Message`
|
||||||
|
The full message.
|
||||||
|
"""
|
||||||
|
|
||||||
|
data = await self._state.http.get_message(self.channel.id, self.id)
|
||||||
|
return self._state.create_message(channel=self.channel, data=data)
|
||||||
|
@ -2952,6 +2952,12 @@ MessageReference
|
|||||||
.. autoclass:: MessageReference
|
.. autoclass:: MessageReference
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
PartialMessage
|
||||||
|
~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. autoclass:: PartialMessage
|
||||||
|
:members:
|
||||||
|
|
||||||
Intents
|
Intents
|
||||||
~~~~~~~~~~
|
~~~~~~~~~~
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user