mirror of
https://github.com/Cog-Creators/Red-DiscordBot.git
synced 2025-11-06 03:08:55 -05:00
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:
parent
47c4edf335
commit
dc817aeeac
@ -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,67 +62,109 @@ 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
|
||||
|
||||
if author == user:
|
||||
return _("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 _(
|
||||
"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.")
|
||||
removed_temp = False
|
||||
|
||||
toggle = await self.config.guild(guild).dm_on_kickban()
|
||||
if toggle:
|
||||
with contextlib.suppress(discord.HTTPException):
|
||||
em = discord.Embed(
|
||||
title=bold(_("You have been banned from {guild}.").format(guild=guild))
|
||||
if not (0 <= days <= 7):
|
||||
return False, _("Invalid days. Must be between 0 and 7.")
|
||||
|
||||
if isinstance(user, discord.Member):
|
||||
if author == user:
|
||||
return (
|
||||
False,
|
||||
_("I cannot let you do that. Self-harm is bad {}").format("\N{PENSIVE FACE}"),
|
||||
)
|
||||
em.add_field(
|
||||
name=_("**Reason**"),
|
||||
value=reason if reason is not None else _("No reason was given."),
|
||||
inline=False,
|
||||
elif not await is_allowed_by_hierarchy(self.bot, self.config, guild, author, user):
|
||||
return (
|
||||
False,
|
||||
_(
|
||||
"I cannot let you do that. You are "
|
||||
"not higher than the user in the role "
|
||||
"hierarchy."
|
||||
),
|
||||
)
|
||||
await user.send(embed=em)
|
||||
elif guild.me.top_role <= user.top_role or user == guild.owner:
|
||||
return False, _("I cannot do that due to Discord hierarchy rules.")
|
||||
|
||||
toggle = await self.config.guild(guild).dm_on_kickban()
|
||||
if toggle:
|
||||
with contextlib.suppress(discord.HTTPException):
|
||||
em = discord.Embed(
|
||||
title=bold(_("You have been banned from {guild}.").format(guild=guild))
|
||||
)
|
||||
em.add_field(
|
||||
name=_("**Reason**"),
|
||||
value=reason if reason is not None else _("No reason was given."),
|
||||
inline=False,
|
||||
)
|
||||
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)
|
||||
try:
|
||||
await guild.ban(user, reason=audit_reason, delete_message_days=days)
|
||||
if removed_temp:
|
||||
log.info(
|
||||
"{}({}) banned {}({}), deleting {} days worth of messages.".format(
|
||||
author.name, author.id, user.name, user.id, str(days)
|
||||
"{}({}) upgraded the tempban for {} to a permaban.".format(
|
||||
author.name, author.id, user.id
|
||||
)
|
||||
)
|
||||
except discord.Forbidden:
|
||||
return _("I'm not allowed to do that.")
|
||||
except Exception as e:
|
||||
log.exception(
|
||||
"{}({}) attempted to kick {}({}), but an error occurred.".format(
|
||||
author.name, author.id, user.name, 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(
|
||||
"{}({}) {}ned {}({}), deleting {} days worth of messages.".format(
|
||||
author.name, author.id, ban_type, username, user.id, str(days)
|
||||
)
|
||||
)
|
||||
)
|
||||
return _("An unexpected error occurred.")
|
||||
success_message = _("Done. That felt good.")
|
||||
except discord.Forbidden:
|
||||
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 {} {}({}), but an error occurred.".format(
|
||||
author.name, author.id, ban_type, username, user.id
|
||||
)
|
||||
)
|
||||
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:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user