diff --git a/docs/cog_guides/mod.rst b/docs/cog_guides/mod.rst index c8dc7da91dc..f412b1500d2 100644 --- a/docs/cog_guides/mod.rst +++ b/docs/cog_guides/mod.rst @@ -266,6 +266,28 @@ and reason as to why they were kicked/banned. * ``[enabled]``: Whether a message should be sent to a user when they are kicked/banned. |bool-input| +.. _mod-command-modset-requirereason: + +"""""""""""""""""""" +modset requirereason +"""""""""""""""""""" + +**Syntax** + +.. code-block:: none + + [p]modset requirereason [enabled] + +**Description** + +Toggle whether a reason is required for mod actions. + +If this is enabled, the bot will require a reason to be provided for all mod actions. + +**Arguments** + +* ``[enabled]``: Whether a reason should be required when performing mod actions. |bool-input| + .. _mod-command-modset-hierarchy: """""""""""""""" diff --git a/redbot/cogs/mod/kickban.py b/redbot/cogs/mod/kickban.py index 28e7f13fd9c..583acb2a8d1 100644 --- a/redbot/cogs/mod/kickban.py +++ b/redbot/cogs/mod/kickban.py @@ -117,6 +117,9 @@ async def ban_user( removed_temp = False + if reason is None and await self.config.guild(guild).require_reason(): + return False, _("You must provide a reason for the ban.") + if not (0 <= days <= 7): return False, _("Invalid days. Must be between 0 and 7.") @@ -303,6 +306,10 @@ async def kick(self, ctx: commands.Context, member: discord.Member, *, reason: s author = ctx.author guild = ctx.guild + if reason is None and await self.config.guild(guild).require_reason(): + await ctx.send(_("You must provide a reason for the kick.")) + return + if author == member: await ctx.send( _("I cannot let you do that. Self-harm is bad {emoji}").format( @@ -428,6 +435,10 @@ async def massban( errors = {} upgrades = [] + if reason is None and await self.config.guild(ctx.guild).require_reason(): + await ctx.send(_("You must provide a reason for the massban.")) + return + async def show_results(): text = _("Banned {num} users from the server.").format( num=humanize_number(len(banned)) @@ -605,6 +616,10 @@ async def tempban( guild = ctx.guild author = ctx.author + if reason is None and await self.config.guild(guild).require_reason(): + await ctx.send(_("You must provide a reason for the temporary ban.")) + return + if author == member: await ctx.send( _("I cannot let you do that. Self-harm is bad {}").format("\N{PENSIVE FACE}") @@ -684,6 +699,10 @@ async def softban(self, ctx: commands.Context, member: discord.Member, *, reason guild = ctx.guild author = ctx.author + if reason is None and await self.config.guild(guild).require_reason(): + await ctx.send(_("You must provide a reason for the softban.")) + return + if author == member: await ctx.send( _("I cannot let you do that. Self-harm is bad {emoji}").format( @@ -771,6 +790,10 @@ async def voicekick( self, ctx: commands.Context, member: discord.Member, *, reason: str = None ): """Kick a member from a voice channel.""" + if reason is None and await self.config.guild(ctx.guild).require_reason(): + await ctx.send(_("You must provide a reason for the voice kick.")) + return + author = ctx.author guild = ctx.guild user_voice_state: discord.VoiceState = member.voice @@ -818,6 +841,10 @@ async def voiceunban( self, ctx: commands.Context, member: discord.Member, *, reason: str = None ): """Unban a user from speaking and listening in the server's voice channels.""" + if reason is None and await self.config.guild(ctx.guild).require_reason(): + await ctx.send(_("You must provide a reason for the voice unban.")) + return + user_voice_state = member.voice if ( await self._voice_perm_check( @@ -859,6 +886,10 @@ async def voiceunban( @commands.admin_or_permissions(mute_members=True, deafen_members=True) async def voiceban(self, ctx: commands.Context, member: discord.Member, *, reason: str = None): """Ban a user from speaking and listening in the server's voice channels.""" + if reason is None and await self.config.guild(ctx.guild).require_reason(): + await ctx.send(_("You must provide a reason for the voice ban.")) + return + user_voice_state: discord.VoiceState = member.voice if ( await self._voice_perm_check( @@ -908,6 +939,10 @@ async def unban( 1. Copy it from the mod log case (if one was created), or 2. Enable Developer Mode, go to Bans in this server's settings, right-click the user and select 'Copy ID'. """ + if reason is None and await self.config.guild(ctx.guild).require_reason(): + await ctx.send(_("You must provide a reason for the unban.")) + return + guild = ctx.guild author = ctx.author audit_reason = get_audit_reason(ctx.author, reason, shorten=True) diff --git a/redbot/cogs/mod/mod.py b/redbot/cogs/mod/mod.py index 3915ce0ce46..17aeb0e7caa 100644 --- a/redbot/cogs/mod/mod.py +++ b/redbot/cogs/mod/mod.py @@ -57,6 +57,7 @@ class Mod( "reinvite_on_unban": False, "current_tempbans": [], "dm_on_kickban": False, + "require_reason": False, "default_days": 0, "default_tempban_duration": 60 * 60 * 24, "track_nicknames": True, diff --git a/redbot/cogs/mod/settings.py b/redbot/cogs/mod/settings.py index 298ed10a590..cd5fc294143 100644 --- a/redbot/cogs/mod/settings.py +++ b/redbot/cogs/mod/settings.py @@ -370,6 +370,29 @@ async def dm(self, ctx: commands.Context, enabled: bool = None): _("Bot will no longer attempt to send a DM to user before kick and ban.") ) + @modset.command() + @commands.guild_only() + async def requirereason(self, ctx: commands.Context, enabled: bool = None): + """ + Toggle whether a reason is required for mod actions. + + If this is enabled, the bot will require a reason to be provided for all mod actions. + """ + guild = ctx.guild + if enabled is None: + setting = await self.config.guild(guild).require_reason() + await ctx.send( + _("Mod action reason requirement is currently set to: {setting}").format( + setting=setting + ) + ) + return + await self.config.guild(guild).require_reason.set(enabled) + if enabled: + await ctx.send(_("Bot will now require a reason for all mod actions.")) + else: + await ctx.send(_("Bot will no longer require a reason for all mod actions.")) + @modset.command() @commands.guild_only() async def defaultdays(self, ctx: commands.Context, days: int = 0):