diff --git a/redbot/cogs/mod/kickban.py b/redbot/cogs/mod/kickban.py index 600461e9101..570e477c41b 100644 --- a/redbot/cogs/mod/kickban.py +++ b/redbot/cogs/mod/kickban.py @@ -16,6 +16,7 @@ format_perms_list, ) from redbot.core.utils.mod import get_audit_reason +from redbot.core.utils.predicates import MessagePredicate from .abc import MixinMeta from .utils import is_allowed_by_hierarchy @@ -575,7 +576,7 @@ def remove_processed(ids): async def tempban( self, ctx: commands.Context, - member: discord.Member, + member: Union[discord.Member, RawUserIdConverter], duration: Optional[commands.TimedeltaConverter] = None, days: Optional[int] = None, *, @@ -596,24 +597,30 @@ async def tempban( """ guild = ctx.guild author = ctx.author + in_server = True + + if isinstance(member, int): + in_server = False + member = self.bot.get_user(member) or discord.Object(id=member) if author == member: await ctx.send( _("I cannot let you do that. Self-harm is bad {}").format("\N{PENSIVE FACE}") ) return - elif not await is_allowed_by_hierarchy(self.bot, self.config, guild, author, member): - await ctx.send( - _( - "I cannot let you do that. You are " - "not higher than the user in the role " - "hierarchy." + elif in_server: + if not await is_allowed_by_hierarchy(self.bot, self.config, guild, author, member): + await ctx.send( + ( + "I cannot let you do that. You are " + "not higher than the user in the role " + "hierarchy." + ) ) - ) - return - elif guild.me.top_role <= member.top_role or member == guild.owner: - await ctx.send(_("I cannot do that due to Discord hierarchy rules.")) - return + return + elif guild.me.top_role <= member.top_role or member == guild.owner: + await ctx.send(_("I cannot do that due to Discord hierarchy rules.")) + return guild_data = await self.config.guild(guild).all() @@ -629,9 +636,64 @@ async def tempban( return invite = await self.get_invite_for_reinvite(ctx, int(duration.total_seconds() + 86400)) - await self.config.member(member).banned_until.set(unban_time.timestamp()) + # Check if user is already banned/tempbanned and prompt for a downgrade + async def prompt_downgrade(banned_until): + if ctx.assume_yes: + return True + + if banned_until: + prompt = await ctx.send( + ( + f"User is already tempbanned expiring , proceed?" + f" (yes/no)" + ) + ) + else: + prompt = await ctx.send( + (f"This will downgrade the ban to a tempban, proceed?" f" (yes/no)") + ) + response = await ctx.bot.wait_for("message", check=MessagePredicate.same_context(ctx)) + + if response.content.lower().startswith("y"): + with contextlib.suppress(discord.NotFound): + await prompt.delete() + with contextlib.suppress(discord.HTTPException): + await response.delete() + return True + else: + await ctx.send("Cancelled.") + return False + + if response.content.lower().startswith("y"): + with contextlib.suppress(discord.NotFound): + await prompt.delete() + with contextlib.suppress(discord.HTTPException): + await response.delete() + return True + else: + await ctx.send("Cancelled.") + return False + + try: + await guild.fetch_ban(member) + except discord.NotFound: + pass + else: + async with self.config.guild(guild).current_tempbans() as current_tempbans: + banned_until = False + if member.id in current_tempbans: + banned_until = await self.config.member_from_ids( + guild.id, member.id + ).banned_until() + if not await prompt_downgrade(banned_until): + return + + await self.config.member_from_ids(guild.id, member.id).banned_until.set( + unban_time.timestamp() + ) async with self.config.guild(guild).current_tempbans() as current_tempbans: - current_tempbans.append(member.id) + if not member.id in current_tempbans: + current_tempbans.append(member.id) with contextlib.suppress(discord.HTTPException): # We don't want blocked DMs preventing us from banning @@ -644,7 +706,8 @@ async def tempban( msg += _("\n\nHere is an invite for when your ban expires: {invite_link}").format( invite_link=invite ) - await member.send(msg) + if in_server: + await member.send(msg) audit_reason = get_audit_reason(author, reason, shorten=True)