Browse Source

Support ban endpoint pagination

pull/7821/head
Rapptz 3 years ago
parent
commit
9acf1db076
  1. 101
      discord/guild.py
  2. 18
      discord/http.py

101
discord/guild.py

@ -2023,29 +2023,112 @@ class Guild(Hashable):
channel: GuildChannel = factory(guild=self, state=self._state, data=data) # type: ignore # channel won't be a private channel channel: GuildChannel = factory(guild=self, state=self._state, data=data) # type: ignore # channel won't be a private channel
return channel return channel
async def bans(self) -> List[BanEntry]: async def bans(
"""|coro| self,
*,
Retrieves all the users that are banned from the guild as a :class:`list` of :class:`BanEntry`. limit: Optional[int] = 1000,
before: Snowflake = MISSING,
after: Snowflake = MISSING,
) -> AsyncIterator[BanEntry]:
"""Retrieves an :term:`asynchronous iterator` of the users that are banned from the guild as a :class:`BanEntry`.
You must have the :attr:`~Permissions.ban_members` permission You must have the :attr:`~Permissions.ban_members` permission
to get this information. to get this information.
.. versionchanged:: 2.0
Due to a breaking change in Discord's API, this now returns a paginated iterator instead of a list.
Examples
---------
Usage ::
async for entry in guild.bans(limit=150):
print(entry.user, entry.reason)
Flattening into a list ::
bans = [entry async for entry in guild.bans(limit=2000)]
# bans is now a list of BanEntry...
All parameters are optional.
Parameters
-----------
limit: Optional[:class:`int`]
The number of bans to retrieve.
If ``None``, it retrieves every guild you have access to. Note, however,
that this would make it a slow operation.
Defaults to ``1000``.
before: :class:`.abc.Snowflake`
Retrieves bans before this user.
after: :class:`.abc.Snowflake`
Retrieve bans after this user.
Raises Raises
------- -------
Forbidden Forbidden
You do not have proper permissions to get the information. You do not have proper permissions to get the information.
HTTPException HTTPException
An error occurred while fetching the information. An error occurred while fetching the information.
TypeError
Both ``after`` and ``before`` were provided, as Discord does not
support this type of pagination.
Returns Yields
-------- --------
List[:class:`BanEntry`] :class:`BanEntry`
A list of :class:`BanEntry` objects. The ban entry of the banned user.
""" """
data: List[BanPayload] = await self._state.http.get_bans(self.id) if before is not MISSING and after is not MISSING:
return [BanEntry(user=User(state=self._state, data=e['user']), reason=e['reason']) for e in data] raise TypeError('bans pagination does not support both before and after')
# This endpoint paginates in ascending order.
endpoint = self._state.http.get_bans
async def _before_strategy(retrieve, before, limit):
before_id = before.id if before else None
data = await endpoint(self.id, limit=retrieve, before=before_id)
if data:
if limit is not None:
limit -= len(data)
before = Object(id=int(data[0]['user']['id']))
return data, before, limit
async def _after_strategy(retrieve, after, limit):
after_id = after.id if after else None
data = await endpoint(self.id, limit=retrieve, after=after_id)
if data:
if limit is not None:
limit -= len(data)
after = Object(id=int(data[-1]['user']['id']))
return data, after, limit
if before:
strategy, state = _before_strategy, before
else:
strategy, state = _after_strategy, after
while True:
retrieve = min(1000 if limit is None else limit, 1000)
if retrieve < 1:
return
data, state, limit = await strategy(retrieve, state, limit)
# Terminate loop on next iteration; there's no data left after this
if len(data) < 1000:
limit = 0
for e in data:
yield BanEntry(user=User(state=self._state, data=e['user']), reason=e['reason'])
async def prune_members( async def prune_members(
self, self,

18
discord/http.py

@ -1175,8 +1175,22 @@ class HTTPClient:
payload['icon'] = icon payload['icon'] = icon
return self.request(Route('POST', '/guilds/templates/{code}', code=code), json=payload) return self.request(Route('POST', '/guilds/templates/{code}', code=code), json=payload)
def get_bans(self, guild_id: Snowflake) -> Response[List[guild.Ban]]: def get_bans(
return self.request(Route('GET', '/guilds/{guild_id}/bans', guild_id=guild_id)) self,
guild_id: Snowflake,
limit: int,
before: Optional[Snowflake] = None,
after: Optional[Snowflake] = None,
) -> Response[List[guild.Ban]]:
params: Dict[str, Any] = {
'limit': limit,
}
if before is not None:
params['before'] = before
if after is not None:
params['after'] = after
return self.request(Route('GET', '/guilds/{guild_id}/bans', guild_id=guild_id), params=params)
def get_ban(self, user_id: Snowflake, guild_id: Snowflake) -> Response[guild.Ban]: def get_ban(self, user_id: Snowflake, guild_id: Snowflake) -> Response[guild.Ban]:
return self.request(Route('GET', '/guilds/{guild_id}/bans/{user_id}', guild_id=guild_id, user_id=user_id)) return self.request(Route('GET', '/guilds/{guild_id}/bans/{user_id}', guild_id=guild_id, user_id=user_id))

Loading…
Cancel
Save