Allow [p]ban to hackban and rename [p]hackban to [p]massban (#4422)

* ban revamp

* black & converters fix

* discord.object

* Update redbot/cogs/admin/admin.py

Co-authored-by: jack1142 <6032823+jack1142@users.noreply.github.com>

* remove discord.user converter

* black

* .

* Update redbot/cogs/mod/kickban.py

Co-authored-by: jack1142 <6032823+jack1142@users.noreply.github.com>

* Update redbot/cogs/mod/kickban.py

Co-authored-by: jack1142 <6032823+jack1142@users.noreply.github.com>

* Update redbot/cogs/mod/kickban.py

Co-authored-by: jack1142 <6032823+jack1142@users.noreply.github.com>

* Update redbot/cogs/mod/kickban.py

Co-authored-by: jack1142 <6032823+jack1142@users.noreply.github.com>

* incomplete

* massban support

* black

* Use 2-tuple to separate result and the message in `ban_user()`

This also fixes the issue with `True` being equal to `1` which caused a problem with previously returned types

* Whoops...

* trailing whitespace...

* I missed this one

* Update kickban.py

* Update kickban.py

Co-authored-by: jack1142 <6032823+jack1142@users.noreply.github.com>
This commit is contained in:
PhenoM4n4n 2020-10-15 14:20:20 -07:00 committed by GitHub
parent 47c4edf335
commit dc817aeeac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -2,7 +2,7 @@ import asyncio
import contextlib
import logging
from datetime import datetime, timedelta, timezone
from typing import Optional, Union
from typing import Optional, Tuple, Union
import discord
from redbot.core import commands, i18n, checks, modlog
@ -62,27 +62,37 @@ class KickBanMixin(MixinMeta):
async def ban_user(
self,
user: discord.Member,
user: Union[discord.Member, discord.User, discord.Object],
ctx: commands.Context,
days: int = 0,
reason: str = None,
create_modlog_case=False,
) -> Union[str, bool]:
) -> Tuple[bool, str]:
author = ctx.author
guild = ctx.guild
removed_temp = False
if not (0 <= days <= 7):
return False, _("Invalid days. Must be between 0 and 7.")
if isinstance(user, discord.Member):
if author == user:
return _("I cannot let you do that. Self-harm is bad {}").format("\N{PENSIVE FACE}")
return (
False,
_("I cannot let you do that. Self-harm is bad {}").format("\N{PENSIVE FACE}"),
)
elif not await is_allowed_by_hierarchy(self.bot, self.config, guild, author, user):
return _(
return (
False,
_(
"I cannot let you do that. You are "
"not higher than the user in the role "
"hierarchy."
),
)
elif guild.me.top_role <= user.top_role or user == guild.owner:
return _("I cannot do that due to Discord hierarchy rules.")
elif not (0 <= days <= 7):
return _("Invalid days. Must be between 0 and 7.")
return False, _("I cannot do that due to Discord hierarchy rules.")
toggle = await self.config.guild(guild).dm_on_kickban()
if toggle:
@ -97,32 +107,64 @@ class KickBanMixin(MixinMeta):
)
await user.send(embed=em)
ban_type = "ban"
else:
tempbans = await self.config.guild(guild).current_tempbans()
ban_list = [ban.user.id for ban in await guild.bans()]
if user.id in ban_list:
if user.id in tempbans:
async with self.config.guild(guild).current_tempbans() as tempbans:
tempbans.remove(user.id)
removed_temp = True
else:
return (
False,
_("User with ID {user_id} is already banned.").format(user_id=user.id),
)
ban_type = "hackban"
audit_reason = get_audit_reason(author, reason)
queue_entry = (guild.id, user.id)
if removed_temp:
log.info(
"{}({}) upgraded the tempban for {} to a permaban.".format(
author.name, author.id, user.id
)
)
success_message = _(
"User with ID {user_id} was upgraded from a temporary to a permanent ban."
).format(user_id=user.id)
else:
username = user.name if hasattr(user, "name") else "Unknown"
try:
await guild.ban(user, reason=audit_reason, delete_message_days=days)
log.info(
"{}({}) banned {}({}), deleting {} days worth of messages.".format(
author.name, author.id, user.name, user.id, str(days)
"{}({}) {}ned {}({}), deleting {} days worth of messages.".format(
author.name, author.id, ban_type, username, user.id, str(days)
)
)
success_message = _("Done. That felt good.")
except discord.Forbidden:
return _("I'm not allowed to do that.")
return False, _("I'm not allowed to do that.")
except discord.NotFound:
return False, _("User with ID {user_id} not found").format(user_id=user.id)
except Exception as e:
log.exception(
"{}({}) attempted to kick {}({}), but an error occurred.".format(
author.name, author.id, user.name, user.id
"{}({}) attempted to {} {}({}), but an error occurred.".format(
author.name, author.id, ban_type, username, user.id
)
)
return _("An unexpected error occurred.")
return False, _("An unexpected error occurred.")
if create_modlog_case:
await modlog.create_case(
self.bot,
guild,
ctx.message.created_at.replace(tzinfo=timezone.utc),
"ban",
ban_type,
user,
author,
reason,
@ -130,7 +172,7 @@ class KickBanMixin(MixinMeta):
channel=None,
)
return True
return True, success_message
async def check_tempban_expirations(self):
while self == self.bot.get_cog("Mod"):
@ -247,13 +289,15 @@ class KickBanMixin(MixinMeta):
async def ban(
self,
ctx: commands.Context,
user: discord.Member,
user: Union[discord.Member, RawUserIds],
days: Optional[int] = None,
*,
reason: str = None,
):
"""Ban a user from this server and optionally delete days of messages.
A user ID should be provided if the user is not a member of this server.
If days is not a number, it's treated as the first word of the reason.
Minimum 0 days, maximum 7. If not specified, defaultdays setting will be used instead."""
@ -261,21 +305,20 @@ class KickBanMixin(MixinMeta):
guild = ctx.guild
if days is None:
days = await self.config.guild(guild).default_days()
if isinstance(user, int):
user = self.bot.get_user(user) or discord.Object(id=user)
result = await self.ban_user(
success_, message = await self.ban_user(
user=user, ctx=ctx, days=days, reason=reason, create_modlog_case=True
)
if result is True:
await ctx.send(_("Done. It was about time."))
elif isinstance(result, str):
await ctx.send(result)
await ctx.send(message)
@commands.command()
@commands.command(aliases=["hackban"])
@commands.guild_only()
@commands.bot_has_permissions(ban_members=True)
@checks.admin_or_permissions(ban_members=True)
async def hackban(
async def massban(
self,
ctx: commands.Context,
user_ids: commands.Greedy[RawUserIds],
@ -283,7 +326,7 @@ class KickBanMixin(MixinMeta):
*,
reason: str = None,
):
"""Preemptively bans user(s) from the server.
"""Mass bans user(s) from the server.
User IDs need to be provided in order to ban
using this command."""
@ -339,7 +382,7 @@ class KickBanMixin(MixinMeta):
# We need to check if a user is tempbanned here because otherwise they won't be processed later on.
continue
else:
errors[user_id] = _("User {user_id} is already banned.").format(
errors[user_id] = _("User with ID {user_id} is already banned.").format(
user_id=user_id
)
@ -358,14 +401,14 @@ class KickBanMixin(MixinMeta):
else:
# Instead of replicating all that handling... gets attr from decorator
try:
result = await self.ban_user(
success, reason = await self.ban_user(
user=user, ctx=ctx, days=days, reason=reason, create_modlog_case=True
)
if result is True:
if success:
banned.append(user_id)
else:
errors[user_id] = _("Failed to ban user {user_id}: {reason}").format(
user_id=user_id, reason=result
user_id=user_id, reason=reason
)
except Exception as e:
errors[user_id] = _("Failed to ban user {user_id}: {reason}").format(
@ -397,13 +440,13 @@ class KickBanMixin(MixinMeta):
await guild.ban(user, reason=audit_reason, delete_message_days=days)
log.info("{}({}) hackbanned {}".format(author.name, author.id, user_id))
except discord.NotFound:
errors[user_id] = _("User {user_id} does not exist.").format(
errors[user_id] = _("User with ID {user_id} not found").format(
user_id=user_id
)
continue
except discord.Forbidden:
errors[user_id] = _(
"Could not ban {user_id}: missing permissions."
"Could not ban user with ID {user_id}: missing permissions."
).format(user_id=user_id)
continue
else: