diff --git a/README.md b/README.md index cea0b84..4f2c2d2 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,8 @@ latex - A simple cog originally by Stevy for v2 that displayes LaTeX expressions luigipoker - Play the Luigi Poker minigame from New Super Mario Brothers. Ported from the v2 version written by themario30. +massunban - Bot Admins or guild Administrators can use this tool to mass unban users via ban reason keywords, or mass unban everyone on the ban list. + noflippedtables - A v3 port of irdumb's v2 cog with a little extra surprise included. Unflip all the tables. nolinks - A very blunt hammer to remove anything that looks like a link. Roles can be whitelisted and it can watch multiple channels. diff --git a/massunban/__init__.py b/massunban/__init__.py new file mode 100644 index 0000000..e7d2027 --- /dev/null +++ b/massunban/__init__.py @@ -0,0 +1,7 @@ +from .massunban import MassUnban + +__red_end_user_data_statement__ = "This cog does not persistently store data or metadata about users." + + +def setup(bot): + bot.add_cog(MassUnban(bot)) diff --git a/massunban/info.json b/massunban/info.json new file mode 100644 index 0000000..7ecb9e1 --- /dev/null +++ b/massunban/info.json @@ -0,0 +1,7 @@ +{ + "author": ["aikaterna"], + "install_msg": "Thanks for installing. Please read the help for the `massunban` command to get started, once you have loaded the cog.", + "short": "Mass unban users.", + "description": "Mass unban users by the ban reason used.", + "tags": ["unban"] +} diff --git a/massunban/massunban.py b/massunban/massunban.py new file mode 100644 index 0000000..226abb7 --- /dev/null +++ b/massunban/massunban.py @@ -0,0 +1,74 @@ +import asyncio +import discord +from redbot.core import checks, commands +from redbot.core.utils.predicates import MessagePredicate + + +class MassUnban(commands.Cog): + """Unban all users, or users with a specific ban reason.""" + + async def red_delete_data_for_user(self, **kwargs): + """Nothing to delete.""" + return + + def __init__(self, bot): + self.bot = bot + + @commands.guild_only() + @commands.command() + @checks.admin_or_permissions(manage_guild=True) + async def massunban(self, ctx, *, ban_reason = None): + """ + Mass unban everyone, or specific people. + + `ban_reason` is what the bot looks for in the original ban reason to qualify a user for an unban. It is case-insensitive. + + When Red is used to ban a user, the ban reason looks like: + `action requested by aikaterna#1393 (id 154497072148643840). reason: bad person` + Using `[p]massunban bad person` will unban this user as "bad person" is contained in the original ban reason. + Using `[p]massunban aikaterna` will unban every user banned by aikaterna, if Red was used to ban them in the first place. + For users banned using the right-click ban option in Discord, the ban reason is only what the mod puts when it asks for a reason, so using the mod name to unban won't work. + + Every unban will show up in your modlog if mod logging is on for unbans. Check `[p]modlogset cases` to verify if mod log creation on unbans is on. + This can mean that your bot will be ratelimited on sending messages if you unban lots of users as it will create a modlog entry for each unban. + """ + try: + banlist = await ctx.guild.bans() + except discord.errors.Forbidden: + msg = "I need the `Ban Members` permission to fetch the ban list for the guild." + await ctx.send(msg) + return + + bancount = len(banlist) + if bancount == 0: + await ctx.send("No users are banned from this server.") + return + + unban_count = 0 + if not ban_reason: + warning_string = ( + "Are you sure you want to unban every banned person on this server?\n" + f"**Please read** `{ctx.prefix}help massunban` **as this action can cause a LOT of modlog messages!**\n" + "Type `Yes` to confirm, or `No` to cancel." + ) + await ctx.send(warning_string) + pred = MessagePredicate.yes_or_no(ctx) + try: + await self.bot.wait_for("message", check=pred, timeout=15) + if pred.result is True: + for ban_entry in banlist: + await ctx.guild.unban(ban_entry.user, reason=f"Mass Unban requested by {str(ctx.author)} ({ctx.author.id})") + await asyncio.sleep(0.5) + unban_count += 1 + else: + return await ctx.send("Alright, I'm not unbanning everyone.") + except asyncio.TimeoutError: + return await ctx.send("Response timed out. Please run this command again if you wish to try again.") + else: + for ban_entry in banlist: + if ban_reason.lower() in ban_entry.reason.lower(): + await ctx.guild.unban(ban_entry.user, reason=f"Mass Unban requested by {str(ctx.author)} ({ctx.author.id})") + await asyncio.sleep(0.5) + unban_count += 1 + + await ctx.send(f"Done. Unbanned {unban_count} users.")