Skip to content

Commit

Permalink
feat: Support bulk banning in guilds (#2421)
Browse files Browse the repository at this point in the history
Signed-off-by: UK <41271523+NeloBlivion@users.noreply.github.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: plun1331 <plun1331@gmail.com>
Co-authored-by: Lala Sabathil <lala@pycord.dev>
  • Loading branch information
4 people authored Apr 26, 2024
1 parent 0536899 commit a1439ba
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 26 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ These changes are available on the `master` branch, but have not yet been releas
([#2417](https://github.com/Pycord-Development/pycord/pull/2417))
- Added `Guild.search_members`.
([#2418](https://github.com/Pycord-Development/pycord/pull/2418))
- Added bulk banning up to 200 users through `Guild.bulk_ban`.
([#2421](https://github.com/Pycord-Development/pycord/pull/2421))
- Added `member` data to the `raw_reaction_remove` event.
([#2412](https://github.com/Pycord-Development/pycord/pull/2412))

Expand Down Expand Up @@ -56,6 +58,12 @@ These changes are available on the `master` branch, but have not yet been releas
- `Guild.query_members` now accepts `limit=None` to retrieve all members.
([#2419](https://github.com/Pycord-Development/pycord/pull/2419))

### Removed

- Removed the `delete_message_days` parameter from ban methods. Please use
`delete_message_seconds` instead.
([#2421](https://github.com/Pycord-Development/pycord/pull/2421))

## [2.5.0] - 2024-03-02

### Added
Expand Down
80 changes: 71 additions & 9 deletions discord/guild.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
Any,
ClassVar,
List,
Literal,
NamedTuple,
Optional,
Sequence,
Expand Down Expand Up @@ -3076,7 +3075,6 @@ async def ban(
user: Snowflake,
*,
delete_message_seconds: int | None = None,
delete_message_days: Literal[0, 1, 2, 3, 4, 5, 6, 7] | None = None,
reason: str | None = None,
) -> None:
"""|coro|
Expand All @@ -3096,9 +3094,6 @@ async def ban(
The number of seconds worth of messages to delete from
the user in the guild. The minimum is 0 and the maximum
is 604800 (i.e. 7 days). The default is 0.
delete_message_days: Optional[:class:`int`]
***Deprecated parameter***, same as ``delete_message_seconds`` but
is used for days instead.
reason: Optional[:class:`str`]
The reason the user got banned.
Expand All @@ -3109,21 +3104,88 @@ async def ban(
HTTPException
Banning failed.
"""
if delete_message_seconds and delete_message_days:

if delete_message_seconds is not None and not (
0 <= delete_message_seconds <= 604800
):
raise TypeError(
"delete_message_seconds and delete_message_days are mutually exclusive."
"delete_message_seconds must be between 0 and 604800 seconds."
)

await self._state.http.ban(
user.id, self.id, delete_message_seconds, reason=reason
)

async def bulk_ban(
self,
*users: Snowflake,
delete_message_seconds: int | None = None,
reason: str | None = None,
) -> list[list[Snowflake], list[Snowflake]]:
r"""|coro|
Bulk ban users from the guild.
The users must meet the :class:`abc.Snowflake` abc.
You must have the :attr:`~Permissions.ban_members` permission to
do this.
Example Usage: ::
# Ban multiple users
successes, failures = await guild.ban(user1, user2, user3, ..., reason="Raid")
# Ban a list of users
successes, failures = await guild.ban(*users)
Parameters
----------
\*users: :class:`abc.Snowflake`
An argument list of users to ban from the guild, up to 200.
delete_message_seconds: Optional[:class:`int`]
The number of seconds worth of messages to delete from
the user in the guild. The minimum is 0 and the maximum
is 604800 (i.e. 7 days). The default is 0.
reason: Optional[:class:`str`]
The reason the users were banned.
Returns
-------
List[List[:class:`abc.Snowflake`], List[:class:`abc.Snowflake`]]
Returns two lists: the first contains members that were successfully banned, while the second is members that could not be banned.
Raises
------
ValueError
You tried to ban more than 200 users.
Forbidden
You do not have the proper permissions to ban.
HTTPException
No users were banned.
"""

if delete_message_seconds is not None and not (
0 <= delete_message_seconds <= 604800
):
raise TypeError(
"delete_message_seconds must be between 0 and 604800 seconds."
)

await self._state.http.ban(
user.id, self.id, delete_message_seconds, delete_message_days, reason=reason
if len(users) > 200 or len(users) < 1:
raise ValueError(
"The number of users to be banned must be between 1 and 200."
)

data = await self._state.http.bulk_ban(
[u.id for u in users],
self.id,
delete_message_seconds,
reason=reason,
)
banned = [u for u in users if str(u.id) in data["banned_users"]]
failed = [u for u in users if str(u.id) in data["failed_users"]]
return banned, failed

async def unban(self, user: Snowflake, *, reason: str | None = None) -> None:
"""|coro|
Expand Down
29 changes: 20 additions & 9 deletions discord/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -907,7 +907,6 @@ def ban(
user_id: Snowflake,
guild_id: Snowflake,
delete_message_seconds: int = None,
delete_message_days: int = None,
reason: str | None = None,
) -> Response[None]:
r = Route(
Expand All @@ -920,17 +919,29 @@ def ban(

if delete_message_seconds:
params["delete_message_seconds"] = delete_message_seconds
elif delete_message_days:
warn_deprecated(
"delete_message_days",
"delete_message_seconds",
"2.2",
reference="https://github.com/discord/discord-api-docs/pull/5219",
)
params["delete_message_days"] = delete_message_days

return self.request(r, params=params, reason=reason)

def bulk_ban(
self,
user_ids: list[Snowflake],
guild_id: Snowflake,
delete_message_seconds: int = None,
reason: str | None = None,
) -> Response[guild.GuildBulkBan]:
r = Route(
"POST",
"/guilds/{guild_id}/bulk-ban",
guild_id=guild_id,
)
payload = {
"user_ids": user_ids,
}
if delete_message_seconds:
payload["delete_message_seconds"] = delete_message_seconds

return self.request(r, json=payload, reason=reason)

def unban(
self, user_id: Snowflake, guild_id: Snowflake, *, reason: str | None = None
) -> Response[None]:
Expand Down
4 changes: 1 addition & 3 deletions discord/member.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
import itertools
import sys
from operator import attrgetter
from typing import TYPE_CHECKING, Any, Literal, TypeVar, Union
from typing import TYPE_CHECKING, Any, TypeVar, Union

import discord.abc

Expand Down Expand Up @@ -684,7 +684,6 @@ async def ban(
self,
*,
delete_message_seconds: int | None = None,
delete_message_days: Literal[0, 1, 2, 3, 4, 5, 6, 7] | None = None,
reason: str | None = None,
) -> None:
"""|coro|
Expand All @@ -695,7 +694,6 @@ async def ban(
self,
reason=reason,
delete_message_seconds=delete_message_seconds,
delete_message_days=delete_message_days,
)

async def unban(self, *, reason: str | None = None) -> None:
Expand Down
5 changes: 5 additions & 0 deletions discord/types/guild.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,3 +185,8 @@ class RolePositionUpdate(TypedDict, total=False):

class GuildMFAModify(TypedDict):
level: Literal[0, 1]


class GuildBulkBan(TypedDict):
banned_users: list[Snowflake]
failed_users: list[Snowflake]
9 changes: 4 additions & 5 deletions docs/ext/commands/commands.rst
Original file line number Diff line number Diff line change
Expand Up @@ -573,11 +573,10 @@ When mixed with the :data:`typing.Optional` converter you can provide simple and
@bot.command()
async def ban(ctx, members: commands.Greedy[discord.Member],
delete_days: typing.Optional[int] = 0, *,
delete_seconds: typing.Optional[int] = 0, *,
reason: str):
"""Mass bans members with an optional delete_days parameter"""
for member in members:
await member.ban(delete_message_days=delete_days, reason=reason)
"""Bulk bans members with an optional delete_seconds parameter"""
await ctx.guild.bulk_ban(*members, delete_message_seconds=delete_seconds, reason=reason)
This command can be invoked any of the following ways:
Expand Down Expand Up @@ -707,7 +706,7 @@ For example, augmenting the example above:
@commands.command()
async def ban(ctx, *, flags: BanFlags):
for member in flags.members:
await member.ban(reason=flags.reason, delete_message_days=flags.days)
await member.ban(reason=flags.reason, delete_message_seconds=flags.days * 60 * 24)
members = ', '.join(str(member) for member in flags.members)
plural = f'{flags.days} days' if flags.days != 1 else f'{flags.days} day'
Expand Down

0 comments on commit a1439ba

Please sign in to comment.