124 lines
4.4 KiB
Python

import logging
from datetime import datetime
from collections import defaultdict, deque
import discord
from redbot.core import i18n, modlog, commands
from redbot.core.utils.mod import is_mod_or_superior
from .abc import MixinMeta
_ = i18n.Translator("Mod", __file__)
log = logging.getLogger("red.mod")
class Events(MixinMeta):
"""
This is a mixin for the core mod cog
Has a bunch of things split off to here.
"""
async def check_duplicates(self, message):
guild = message.guild
author = message.author
guild_cache = self.cache.get(guild.id, None)
if guild_cache is None:
repeats = await self.config.guild(guild).delete_repeats()
if repeats == -1:
return False
guild_cache = self.cache[guild.id] = defaultdict(lambda: deque(maxlen=repeats))
if not message.content:
return False
guild_cache[author].append(message.content)
msgs = guild_cache[author]
if len(msgs) == msgs.maxlen and len(set(msgs)) == 1:
try:
await message.delete()
return True
except discord.HTTPException:
pass
return False
async def check_mention_spam(self, message):
guild = message.guild
author = message.author
max_mentions = await self.config.guild(guild).ban_mention_spam()
if max_mentions:
mentions = set(message.mentions)
if len(mentions) >= max_mentions:
try:
await guild.ban(author, reason=_("Mention spam (Autoban)"))
except discord.HTTPException:
log.info(
"Failed to ban member for mention spam in server {}.".format(guild.id)
)
else:
await modlog.create_case(
self.bot,
guild,
message.created_at,
"ban",
author,
guild.me,
_("Mention spam (Autoban)"),
until=None,
channel=None,
)
return True
return False
@commands.Cog.listener()
async def on_message(self, message):
author = message.author
if message.guild is None or self.bot.user == author:
return
if await self.bot.cog_disabled_in_guild(self, message.guild):
return
valid_user = isinstance(author, discord.Member) and not author.bot
if not valid_user:
return
# Bots and mods or superior are ignored from the filter
mod_or_superior = await is_mod_or_superior(self.bot, obj=author)
if mod_or_superior:
return
# As are anyone configured to be
if await self.bot.is_automod_immune(message):
return
deleted = await self.check_duplicates(message)
if not deleted:
await self.check_mention_spam(message)
@commands.Cog.listener()
async def on_user_update(self, before: discord.User, after: discord.User):
if before.name != after.name:
async with self.config.user(before).past_names() as name_list:
while None in name_list: # clean out null entries from a bug
name_list.remove(None)
if after.name in name_list:
# Ensure order is maintained without duplicates occurring
name_list.remove(after.name)
name_list.append(after.name)
while len(name_list) > 20:
name_list.pop(0)
@commands.Cog.listener()
async def on_member_update(self, before: discord.Member, after: discord.Member):
if before.nick != after.nick and after.nick is not None:
guild = after.guild
if (not guild) or await self.bot.cog_disabled_in_guild(self, guild):
return
async with self.config.member(before).past_nicks() as nick_list:
while None in nick_list: # clean out null entries from a bug
nick_list.remove(None)
if after.nick in nick_list:
nick_list.remove(after.nick)
nick_list.append(after.nick)
while len(nick_list) > 20:
nick_list.pop(0)