mirror of
https://github.com/Rapptz/discord.py.git
synced 2025-08-20 10:00:46 +00:00
Update to support new pin endpoints
This commit is contained in:
parent
50caa3c82c
commit
705eb2c2a5
152
discord/abc.py
152
discord/abc.py
@ -34,8 +34,10 @@ from typing import (
|
|||||||
AsyncIterator,
|
AsyncIterator,
|
||||||
Callable,
|
Callable,
|
||||||
Dict,
|
Dict,
|
||||||
|
Generator,
|
||||||
Iterable,
|
Iterable,
|
||||||
List,
|
List,
|
||||||
|
Literal,
|
||||||
Optional,
|
Optional,
|
||||||
TYPE_CHECKING,
|
TYPE_CHECKING,
|
||||||
Protocol,
|
Protocol,
|
||||||
@ -61,6 +63,7 @@ from .voice_client import VoiceClient, VoiceProtocol
|
|||||||
from .sticker import GuildSticker, StickerItem
|
from .sticker import GuildSticker, StickerItem
|
||||||
from . import utils
|
from . import utils
|
||||||
from .flags import InviteFlags
|
from .flags import InviteFlags
|
||||||
|
import warnings
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'Snowflake',
|
'Snowflake',
|
||||||
@ -114,6 +117,11 @@ if TYPE_CHECKING:
|
|||||||
MessageableChannel = Union[PartialMessageableChannel, GroupChannel]
|
MessageableChannel = Union[PartialMessageableChannel, GroupChannel]
|
||||||
SnowflakeTime = Union["Snowflake", datetime]
|
SnowflakeTime = Union["Snowflake", datetime]
|
||||||
|
|
||||||
|
class PinnedMessage(Message):
|
||||||
|
pinned_at: datetime
|
||||||
|
pinned: Literal[True]
|
||||||
|
|
||||||
|
|
||||||
MISSING = utils.MISSING
|
MISSING = utils.MISSING
|
||||||
|
|
||||||
|
|
||||||
@ -125,6 +133,26 @@ class _Undefined:
|
|||||||
_undefined: Any = _Undefined()
|
_undefined: Any = _Undefined()
|
||||||
|
|
||||||
|
|
||||||
|
class _PinsIterator:
|
||||||
|
def __init__(self, iterator: AsyncIterator[PinnedMessage]) -> None:
|
||||||
|
self.__iterator: AsyncIterator[PinnedMessage] = iterator
|
||||||
|
|
||||||
|
def __await__(self) -> Generator[Any, None, List[PinnedMessage]]:
|
||||||
|
warnings.warn(
|
||||||
|
"`await <channel>.pins()` is deprecated; use `async for message in <channel>.pins()` instead.",
|
||||||
|
DeprecationWarning,
|
||||||
|
stacklevel=2,
|
||||||
|
)
|
||||||
|
|
||||||
|
async def gather() -> List[PinnedMessage]:
|
||||||
|
return [msg async for msg in self.__iterator]
|
||||||
|
|
||||||
|
return gather().__await__()
|
||||||
|
|
||||||
|
def __aiter__(self) -> AsyncIterator[PinnedMessage]:
|
||||||
|
return self.__iterator
|
||||||
|
|
||||||
|
|
||||||
async def _single_delete_strategy(messages: Iterable[Message], *, reason: Optional[str] = None):
|
async def _single_delete_strategy(messages: Iterable[Message], *, reason: Optional[str] = None):
|
||||||
for m in messages:
|
for m in messages:
|
||||||
try:
|
try:
|
||||||
@ -1754,17 +1782,119 @@ class Messageable:
|
|||||||
data = await self._state.http.get_message(channel.id, id)
|
data = await self._state.http.get_message(channel.id, id)
|
||||||
return self._state.create_message(channel=channel, data=data)
|
return self._state.create_message(channel=channel, data=data)
|
||||||
|
|
||||||
async def pins(self) -> List[Message]:
|
async def __pins(
|
||||||
"""|coro|
|
self,
|
||||||
|
*,
|
||||||
|
limit: Optional[int] = 50,
|
||||||
|
before: Optional[SnowflakeTime] = None,
|
||||||
|
oldest_first: bool = False,
|
||||||
|
) -> AsyncIterator[PinnedMessage]:
|
||||||
|
channel = await self._get_channel()
|
||||||
|
state = self._state
|
||||||
|
max_limit: int = 50
|
||||||
|
|
||||||
Retrieves all messages that are currently pinned in the channel.
|
time: Optional[str] = (
|
||||||
|
(before if isinstance(before, datetime) else utils.snowflake_time(before.id)).isoformat()
|
||||||
|
if before is not None
|
||||||
|
else None
|
||||||
|
)
|
||||||
|
|
||||||
|
while True:
|
||||||
|
retrieve = max_limit if limit is None else min(limit, max_limit)
|
||||||
|
if retrieve < 1:
|
||||||
|
break
|
||||||
|
|
||||||
|
data = await self._state.http.pins_from(
|
||||||
|
channel_id=channel.id,
|
||||||
|
limit=retrieve,
|
||||||
|
before=time,
|
||||||
|
)
|
||||||
|
|
||||||
|
items = data and data['items']
|
||||||
|
if items:
|
||||||
|
if limit is not None:
|
||||||
|
limit -= len(items)
|
||||||
|
|
||||||
|
time = items[-1]['pinned_at']
|
||||||
|
|
||||||
|
# Terminate loop on next iteration; there's no data left after this
|
||||||
|
if len(items) < max_limit or not data['has_more']:
|
||||||
|
limit = 0
|
||||||
|
|
||||||
|
if oldest_first:
|
||||||
|
items = reversed(items)
|
||||||
|
|
||||||
|
count = 0
|
||||||
|
for count, m in enumerate(items, start=1):
|
||||||
|
message: Message = state.create_message(channel=channel, data=m['message'])
|
||||||
|
message._pinned_at = utils.parse_time(m['pinned_at'])
|
||||||
|
yield message # pyright: ignore[reportReturnType]
|
||||||
|
|
||||||
|
if count < max_limit:
|
||||||
|
break
|
||||||
|
|
||||||
|
def pins(
|
||||||
|
self,
|
||||||
|
*,
|
||||||
|
limit: Optional[int] = 50,
|
||||||
|
before: Optional[SnowflakeTime] = None,
|
||||||
|
oldest_first: bool = False,
|
||||||
|
) -> _PinsIterator:
|
||||||
|
"""Retrieves an :term:`asynchronous iterator` of the pinned messages in the channel.
|
||||||
|
|
||||||
|
You must have :attr:`~discord.Permissions.view_channel` and
|
||||||
|
:attr:`~discord.Permissions.read_message_history` in order to use this.
|
||||||
|
|
||||||
|
.. versionchanged:: 2.6
|
||||||
|
|
||||||
|
Due to a change in Discord's API, this now returns a paginated iterator instead of a list.
|
||||||
|
|
||||||
|
For backwards compatibility, you can still retrieve a list of pinned messages by
|
||||||
|
using ``await`` on the returned object. This is however deprecated.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
Due to a limitation with the Discord API, the :class:`.Message`
|
Due to a limitation with the Discord API, the :class:`.Message`
|
||||||
objects returned by this method do not contain complete
|
object returned by this method does not contain complete
|
||||||
:attr:`.Message.reactions` data.
|
:attr:`.Message.reactions` data.
|
||||||
|
|
||||||
|
Examples
|
||||||
|
---------
|
||||||
|
|
||||||
|
Usage ::
|
||||||
|
|
||||||
|
counter = 0
|
||||||
|
async for message in channel.pins(limit=250):
|
||||||
|
counter += 1
|
||||||
|
|
||||||
|
Flattening into a list: ::
|
||||||
|
|
||||||
|
messages = [message async for message in channel.pins(limit=50)]
|
||||||
|
# messages is now a list of Message...
|
||||||
|
|
||||||
|
All parameters are optional.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
-----------
|
||||||
|
limit: Optional[int]
|
||||||
|
The number of pinned messages to retrieve. If ``None``, it retrieves
|
||||||
|
every pinned message in the channel. Note, however, that this would
|
||||||
|
make it a slow operation.
|
||||||
|
Defaults to ``50``.
|
||||||
|
|
||||||
|
.. versionadded:: 2.6
|
||||||
|
before: Optional[Union[:class:`datetime.datetime`, :class:`.abc.Snowflake`]]
|
||||||
|
Retrieve pinned messages before this time or snowflake.
|
||||||
|
If a datetime is provided, it is recommended to use a UTC aware datetime.
|
||||||
|
If the datetime is naive, it is assumed to be local time.
|
||||||
|
|
||||||
|
.. versionadded:: 2.6
|
||||||
|
oldest_first: :class:`bool`
|
||||||
|
If set to ``True``, return messages in oldest pin->newest pin order.
|
||||||
|
Defaults to ``False``.
|
||||||
|
|
||||||
|
.. versionadded:: 2.6
|
||||||
|
|
||||||
Raises
|
Raises
|
||||||
-------
|
-------
|
||||||
~discord.Forbidden
|
~discord.Forbidden
|
||||||
@ -1772,16 +1902,12 @@ class Messageable:
|
|||||||
~discord.HTTPException
|
~discord.HTTPException
|
||||||
Retrieving the pinned messages failed.
|
Retrieving the pinned messages failed.
|
||||||
|
|
||||||
Returns
|
Yields
|
||||||
--------
|
-------
|
||||||
List[:class:`~discord.Message`]
|
:class:`~discord.Message`
|
||||||
The messages that are currently pinned.
|
The pinned message with :attr:`.Message.pinned_at` set.
|
||||||
"""
|
"""
|
||||||
|
return _PinsIterator(self.__pins(limit=limit, before=before, oldest_first=oldest_first))
|
||||||
channel = await self._get_channel()
|
|
||||||
state = self._state
|
|
||||||
data = await state.http.pins_from(channel.id)
|
|
||||||
return [state.create_message(channel=channel, data=m) for m in data]
|
|
||||||
|
|
||||||
async def history(
|
async def history(
|
||||||
self,
|
self,
|
||||||
|
@ -1047,7 +1047,7 @@ class HTTPClient:
|
|||||||
def pin_message(self, channel_id: Snowflake, message_id: Snowflake, reason: Optional[str] = None) -> Response[None]:
|
def pin_message(self, channel_id: Snowflake, message_id: Snowflake, reason: Optional[str] = None) -> Response[None]:
|
||||||
r = Route(
|
r = Route(
|
||||||
'PUT',
|
'PUT',
|
||||||
'/channels/{channel_id}/pins/{message_id}',
|
'/channels/{channel_id}/messages/pins/{message_id}',
|
||||||
channel_id=channel_id,
|
channel_id=channel_id,
|
||||||
message_id=message_id,
|
message_id=message_id,
|
||||||
)
|
)
|
||||||
@ -1056,14 +1056,25 @@ class HTTPClient:
|
|||||||
def unpin_message(self, channel_id: Snowflake, message_id: Snowflake, reason: Optional[str] = None) -> Response[None]:
|
def unpin_message(self, channel_id: Snowflake, message_id: Snowflake, reason: Optional[str] = None) -> Response[None]:
|
||||||
r = Route(
|
r = Route(
|
||||||
'DELETE',
|
'DELETE',
|
||||||
'/channels/{channel_id}/pins/{message_id}',
|
'/channels/{channel_id}/messages/pins/{message_id}',
|
||||||
channel_id=channel_id,
|
channel_id=channel_id,
|
||||||
message_id=message_id,
|
message_id=message_id,
|
||||||
)
|
)
|
||||||
return self.request(r, reason=reason)
|
return self.request(r, reason=reason)
|
||||||
|
|
||||||
def pins_from(self, channel_id: Snowflake) -> Response[List[message.Message]]:
|
def pins_from(
|
||||||
return self.request(Route('GET', '/channels/{channel_id}/pins', channel_id=channel_id))
|
self,
|
||||||
|
channel_id: Snowflake,
|
||||||
|
limit: Optional[int] = None,
|
||||||
|
before: Optional[str] = None,
|
||||||
|
) -> Response[message.ChannelPins]:
|
||||||
|
params = {}
|
||||||
|
if before is not None:
|
||||||
|
params['before'] = before
|
||||||
|
if limit is not None:
|
||||||
|
params['limit'] = limit
|
||||||
|
|
||||||
|
return self.request(Route('GET', '/channels/{channel_id}/messages/pins', channel_id=channel_id), params=params)
|
||||||
|
|
||||||
# Member management
|
# Member management
|
||||||
|
|
||||||
|
@ -2185,6 +2185,7 @@ class Message(PartialMessage, Hashable):
|
|||||||
'call',
|
'call',
|
||||||
'purchase_notification',
|
'purchase_notification',
|
||||||
'message_snapshots',
|
'message_snapshots',
|
||||||
|
'_pinned_at',
|
||||||
)
|
)
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
@ -2224,6 +2225,8 @@ class Message(PartialMessage, Hashable):
|
|||||||
self.application_id: Optional[int] = utils._get_as_snowflake(data, 'application_id')
|
self.application_id: Optional[int] = utils._get_as_snowflake(data, 'application_id')
|
||||||
self.stickers: List[StickerItem] = [StickerItem(data=d, state=state) for d in data.get('sticker_items', [])]
|
self.stickers: List[StickerItem] = [StickerItem(data=d, state=state) for d in data.get('sticker_items', [])]
|
||||||
self.message_snapshots: List[MessageSnapshot] = MessageSnapshot._from_value(state, data.get('message_snapshots'))
|
self.message_snapshots: List[MessageSnapshot] = MessageSnapshot._from_value(state, data.get('message_snapshots'))
|
||||||
|
# Set by Messageable.pins
|
||||||
|
self._pinned_at: Optional[datetime.datetime] = None
|
||||||
|
|
||||||
self.poll: Optional[Poll] = None
|
self.poll: Optional[Poll] = None
|
||||||
try:
|
try:
|
||||||
@ -2644,6 +2647,18 @@ class Message(PartialMessage, Hashable):
|
|||||||
# Fall back to guild threads in case one was created after the message
|
# Fall back to guild threads in case one was created after the message
|
||||||
return self._thread or self.guild.get_thread(self.id)
|
return self._thread or self.guild.get_thread(self.id)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def pinned_at(self) -> Optional[datetime.datetime]:
|
||||||
|
"""Optional[:class:`datetime.datetime`]: An aware UTC datetime object containing the time
|
||||||
|
when the message was pinned.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
This is only set for messages that are returned by :meth:`abc.Messageable.pins`.
|
||||||
|
|
||||||
|
.. versionadded:: 2.6
|
||||||
|
"""
|
||||||
|
return self._pinned_at
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@deprecated('interaction_metadata')
|
@deprecated('interaction_metadata')
|
||||||
def interaction(self) -> Optional[MessageInteraction]:
|
def interaction(self) -> Optional[MessageInteraction]:
|
||||||
|
@ -237,3 +237,13 @@ class AllowedMentions(TypedDict):
|
|||||||
roles: SnowflakeList
|
roles: SnowflakeList
|
||||||
users: SnowflakeList
|
users: SnowflakeList
|
||||||
replied_user: bool
|
replied_user: bool
|
||||||
|
|
||||||
|
|
||||||
|
class MessagePin(TypedDict):
|
||||||
|
pinned_at: str
|
||||||
|
message: Message
|
||||||
|
|
||||||
|
|
||||||
|
class ChannelPins(TypedDict):
|
||||||
|
items: List[MessagePin]
|
||||||
|
has_more: bool
|
||||||
|
Loading…
x
Reference in New Issue
Block a user