[Mod] Allow admins to choose amount of repeats for "deleterepeats" (#2437)

* feat(mod): configurable amount of repeats for "deleterepeats"

resolves #2267

* fix(mod): check user input instead of changing it if it's invalid

* fix(mod): only purge cache when argument is valid

* perf(mod): fetch repeats from config only when guild not in cache
This commit is contained in:
jack1142 2019-04-23 16:01:20 +02:00 committed by Michael H
parent 47723cee33
commit 460b4bb3f2
4 changed files with 90 additions and 25 deletions

View File

@ -2,5 +2,7 @@ from redbot.core.bot import Red
from .mod import Mod from .mod import Mod
def setup(bot: Red): async def setup(bot: Red):
bot.add_cog(Mod(bot)) cog = Mod(bot)
await cog.initialize()
bot.add_cog(cog)

View File

@ -1,4 +1,5 @@
from datetime import datetime from datetime import datetime
from collections import defaultdict, deque
import discord import discord
from redbot.core import i18n, modlog from redbot.core import i18n, modlog
@ -19,12 +20,19 @@ class Events(MixinMeta):
guild = message.guild guild = message.guild
author = message.author author = message.author
if await self.settings.guild(guild).delete_repeats(): guild_cache = self.cache.get(guild.id, None)
if guild_cache is None:
repeats = await self.settings.guild(guild).delete_repeats()
if repeats == -1:
return False
guild_cache = self.cache[guild.id] = defaultdict(lambda: deque(maxlen=repeats))
if not message.content: if not message.content:
return False return False
self.cache[author].append(message)
msgs = self.cache[author] guild_cache[author].append(message.content)
if len(msgs) == 3 and msgs[0].content == msgs[1].content == msgs[2].content: msgs = guild_cache[author]
if len(msgs) == msgs.maxlen and len(set(msgs)) == 1:
try: try:
await message.delete() await message.delete()
return True return True

View File

@ -1,4 +1,4 @@
from collections import deque, defaultdict from collections import defaultdict
from typing import List, Tuple from typing import List, Tuple
import discord import discord
@ -15,14 +15,18 @@ from .settings import ModSettings
_ = T_ = Translator("Mod", __file__) _ = T_ = Translator("Mod", __file__)
__version__ = "1.0.0"
@cog_i18n(_) @cog_i18n(_)
class Mod(ModSettings, Events, KickBanMixin, MoveToCore, MuteMixin, ModInfo, commands.Cog): class Mod(ModSettings, Events, KickBanMixin, MoveToCore, MuteMixin, ModInfo, commands.Cog):
"""Moderation tools.""" """Moderation tools."""
default_global_settings = {"version": ""}
default_guild_settings = { default_guild_settings = {
"ban_mention_spam": False, "ban_mention_spam": False,
"delete_repeats": False, "delete_repeats": -1,
"ignored": False, "ignored": False,
"respect_hierarchy": True, "respect_hierarchy": True,
"delete_delay": -1, "delete_delay": -1,
@ -41,21 +45,39 @@ class Mod(ModSettings, Events, KickBanMixin, MoveToCore, MuteMixin, ModInfo, com
self.bot = bot self.bot = bot
self.settings = Config.get_conf(self, 4961522000, force_registration=True) self.settings = Config.get_conf(self, 4961522000, force_registration=True)
self.settings.register_global(**self.default_global_settings)
self.settings.register_guild(**self.default_guild_settings) self.settings.register_guild(**self.default_guild_settings)
self.settings.register_channel(**self.default_channel_settings) self.settings.register_channel(**self.default_channel_settings)
self.settings.register_member(**self.default_member_settings) self.settings.register_member(**self.default_member_settings)
self.settings.register_user(**self.default_user_settings) self.settings.register_user(**self.default_user_settings)
self.ban_queue: List[Tuple[int, int]] = [] self.ban_queue: List[Tuple[int, int]] = []
self.unban_queue: List[Tuple[int, int]] = [] self.unban_queue: List[Tuple[int, int]] = []
self.cache: dict = defaultdict(lambda: deque(maxlen=3)) self.cache: dict = {}
self.registration_task = self.bot.loop.create_task(self._casetype_registration()) self.registration_task = self.bot.loop.create_task(self._casetype_registration())
self.tban_expiry_task = self.bot.loop.create_task(self.check_tempban_expirations()) self.tban_expiry_task = self.bot.loop.create_task(self.check_tempban_expirations())
self.last_case: dict = defaultdict(dict) self.last_case: dict = defaultdict(dict)
async def initialize(self):
await self._maybe_update_config()
def __unload(self): def __unload(self):
self.registration_task.cancel() self.registration_task.cancel()
self.tban_expiry_task.cancel() self.tban_expiry_task.cancel()
async def _maybe_update_config(self):
"""Maybe update `delete_delay` value set by Config prior to Mod 1.0.0."""
if await self.settings.version():
return
guild_dict = await self.settings.all_guilds()
for guild_id, info in guild_dict.items():
delete_repeats = info.get("delete_repeats", False)
if delete_repeats:
val = 3
else:
val = -1
await self.settings.guild(discord.Object(id=guild_id)).delete_repeats.set(val)
await self.settings.version.set(__version__)
@staticmethod @staticmethod
async def _casetype_registration(): async def _casetype_registration():
try: try:

View File

@ -1,3 +1,5 @@
from collections import defaultdict, deque
from redbot.core import commands, i18n, checks from redbot.core import commands, i18n, checks
from redbot.core.utils.chat_formatting import box from redbot.core.utils.chat_formatting import box
@ -25,8 +27,10 @@ class ModSettings(MixinMeta):
delete_delay = await self.settings.guild(guild).delete_delay() delete_delay = await self.settings.guild(guild).delete_delay()
reinvite_on_unban = await self.settings.guild(guild).reinvite_on_unban() reinvite_on_unban = await self.settings.guild(guild).reinvite_on_unban()
msg = "" msg = ""
msg += _("Delete repeats: {yes_or_no}\n").format( msg += _("Delete repeats: {num_repeats}\n").format(
yes_or_no=_("Yes") if delete_repeats else _("No") num_repeats=_("after {num} repeats").format(num=delete_repeats)
if delete_repeats != -1
else _("No")
) )
msg += _("Ban mention spam: {num_mentions}\n").format( msg += _("Ban mention spam: {num_mentions}\n").format(
num_mentions=_("{num} mentions").format(num=ban_mention_spam) num_mentions=_("{num} mentions").format(num=ban_mention_spam)
@ -101,15 +105,44 @@ class ModSettings(MixinMeta):
@modset.command() @modset.command()
@commands.guild_only() @commands.guild_only()
async def deleterepeats(self, ctx: commands.Context): async def deleterepeats(self, ctx: commands.Context, repeats: int = None):
"""Enable auto-deletion of repeated messages.""" """Enable auto-deletion of repeated messages.
Must be between 2 and 20.
Set to -1 to disable this feature.
"""
guild = ctx.guild guild = ctx.guild
cur_setting = await self.settings.guild(guild).delete_repeats() if repeats is not None:
if not cur_setting: if repeats == -1:
await self.settings.guild(guild).delete_repeats.set(True) await self.settings.guild(guild).delete_repeats.set(repeats)
await ctx.send(_("Messages repeated up to 3 times will be deleted.")) self.cache.pop(guild.id, None) # remove cache with old repeat limits
await ctx.send(_("Repeated messages will be ignored."))
elif 2 <= repeats <= 20:
await self.settings.guild(guild).delete_repeats.set(repeats)
# purge and update cache to new repeat limits
self.cache[guild.id] = defaultdict(lambda: deque(maxlen=repeats))
await ctx.send(
_("Messages repeated up to {num} times will be deleted.").format(num=repeats)
)
else:
await ctx.send(
_(
"Number of repeats must be between 2 and 20"
" or equal to -1 if you want to disable this feature!"
)
)
else:
repeats = await self.settings.guild(guild).delete_repeats()
if repeats != -1:
await ctx.send(
_(
"Bot will delete repeated messages after"
" {num} repeats. Set this value to -1 to"
" ignore repeated messages"
).format(num=repeats)
)
else: else:
await self.settings.guild(guild).delete_repeats.set(False)
await ctx.send(_("Repeated messages will be ignored.")) await ctx.send(_("Repeated messages will be ignored."))
@modset.command() @modset.command()