From e6db94cf58dc8be7879e15697e8669597845c7ef Mon Sep 17 00:00:00 2001 From: L3viathan Date: Tue, 16 Dec 2025 16:08:55 +0100 Subject: [PATCH] Require confirmation before kicking elevated user This was already the case when attempting to ban an elevated user, but kicks have almost the same consequences (e.g. loss of roles), so we should prevent it in that case, too. --- bot/exts/moderation/infraction/_utils.py | 14 +++++++------- bot/exts/moderation/infraction/_views.py | 6 +++--- bot/exts/moderation/infraction/infractions.py | 5 ++++- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/bot/exts/moderation/infraction/_utils.py b/bot/exts/moderation/infraction/_utils.py index 4062fac039..752f3ad38a 100644 --- a/bot/exts/moderation/infraction/_utils.py +++ b/bot/exts/moderation/infraction/_utils.py @@ -12,7 +12,7 @@ from bot.constants import Categories, Channels, Colours, Icons, MODERATION_ROLES, STAFF_AND_COMMUNITY_ROLES from bot.converters import DurationOrExpiry, MemberOrUser from bot.errors import InvalidInfractedUserError -from bot.exts.moderation.infraction._views import BanConfirmationView +from bot.exts.moderation.infraction._views import InfractionConfirmationView from bot.log import get_logger from bot.utils import time from bot.utils.channel import is_in_category, is_mod_channel @@ -328,9 +328,9 @@ def cap_timeout_duration(duration: datetime.datetime | relativedelta) -> tuple[b return capped, duration -async def confirm_elevated_user_ban(ctx: Context, user: MemberOrUser) -> bool: +async def confirm_elevated_user_infraction(ctx: Context, user: MemberOrUser) -> bool: """ - If user has an elevated role, require confirmation before banning. + If user has an elevated role, require confirmation before issuing infraction. A member with the staff or community roles are considered elevated. @@ -339,24 +339,24 @@ async def confirm_elevated_user_ban(ctx: Context, user: MemberOrUser) -> bool: if not isinstance(user, Member) or not any(role.id in STAFF_AND_COMMUNITY_ROLES for role in user.roles): return True - confirmation_view = BanConfirmationView( + confirmation_view = InfractionConfirmationView( allowed_users=(ctx.author.id,), allowed_roles=MODERATION_ROLES, timeout=10, ) confirmation_view.message = await ctx.send( - f"{user.mention} has an elevated role. Are you sure you want to ban them?", + f"{user.mention} has an elevated role. Are you sure you want to infract them?", view=confirmation_view, allowed_mentions=discord.AllowedMentions.none(), ) timed_out = await confirmation_view.wait() if timed_out: - log.trace(f"Attempted ban of user {user} by moderator {ctx.author} cancelled due to timeout.") + log.trace(f"Attempted infraction of user {user} by moderator {ctx.author} cancelled due to timeout.") return False if confirmation_view.confirmed is False: - log.trace(f"Attempted ban of user {user} by moderator {ctx.author} cancelled due to manual cancel.") + log.trace(f"Attempted infraction of user {user} by moderator {ctx.author} cancelled due to manual cancel.") return False return True diff --git a/bot/exts/moderation/infraction/_views.py b/bot/exts/moderation/infraction/_views.py index 26287d6e6e..f539fa768c 100644 --- a/bot/exts/moderation/infraction/_views.py +++ b/bot/exts/moderation/infraction/_views.py @@ -6,16 +6,16 @@ from pydis_core.utils import interactions -class BanConfirmationView(interactions.ViewWithUserAndRoleCheck): +class InfractionConfirmationView(interactions.ViewWithUserAndRoleCheck): """A confirmation view to be sent before issuing potentially suspect infractions.""" def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) self.confirmed = False - @discord.ui.button(label="Ban", style=ButtonStyle.red) + @discord.ui.button(label="Infract", style=ButtonStyle.red) async def confirm(self, interaction: Interaction, button: Button) -> None: - """Callback coroutine that is called when the "Ban" button is pressed.""" + """Callback coroutine that is called when the "Infract" button is pressed.""" self.confirmed = True await interaction.response.defer() self.stop() diff --git a/bot/exts/moderation/infraction/infractions.py b/bot/exts/moderation/infraction/infractions.py index efe70d0216..7ce574a074 100644 --- a/bot/exts/moderation/infraction/infractions.py +++ b/bot/exts/moderation/infraction/infractions.py @@ -427,6 +427,9 @@ async def apply_kick(self, ctx: Context, user: Member, reason: str | None, **kwa await ctx.send(":x: I can't kick users above or equal to me in the role hierarchy.") return + if not await _utils.confirm_elevated_user_infraction(ctx, user): + return + infraction = await _utils.post_infraction(ctx, user, "kick", reason, active=False, **kwargs) if infraction is None: return @@ -459,7 +462,7 @@ async def apply_ban( await ctx.send(":x: I can't ban users above or equal to me in the role hierarchy.") return None - if not await _utils.confirm_elevated_user_ban(ctx, user): + if not await _utils.confirm_elevated_user_infraction(ctx, user): return None # In the case of a permanent ban, we don't need get_active_infractions to tell us if one is active