mirror of
https://github.com/Cog-Creators/Red-DiscordBot.git
synced 2025-11-06 03:08:55 -05:00
Automated mod action immunity settings (#2129)
Refactors, and fixes some logic in filter which was encountered while applying the settings to core
This commit is contained in:
parent
84ac5f3952
commit
f8558b98c1
@ -249,70 +249,41 @@ class Filter:
|
||||
mod_or_superior = await is_mod_or_superior(self.bot, obj=author)
|
||||
if mod_or_superior:
|
||||
return
|
||||
|
||||
await self.check_filter(message)
|
||||
|
||||
async def on_message_edit(self, _, message):
|
||||
author = message.author
|
||||
if message.guild is None or self.bot.user == author:
|
||||
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:
|
||||
# As is anyone configured to be
|
||||
if await self.bot.is_automod_immune(message):
|
||||
return
|
||||
|
||||
await self.check_filter(message)
|
||||
|
||||
async def on_message_edit(self, _prior, message):
|
||||
# message content has to change for non-bot's currently.
|
||||
# if this changes, we should compare before passing it.
|
||||
await self.on_message(message)
|
||||
|
||||
async def on_member_update(self, before: discord.Member, after: discord.Member):
|
||||
if not after.guild.me.guild_permissions.manage_nicknames:
|
||||
return # No permissions to manage nicknames, so can't do anything
|
||||
word_list = await self.settings.guild(after.guild).filter()
|
||||
filter_names = await self.settings.guild(after.guild).filter_names()
|
||||
name_to_use = await self.settings.guild(after.guild).filter_default_name()
|
||||
if not filter_names:
|
||||
return
|
||||
|
||||
name_filtered = False
|
||||
nick_filtered = False
|
||||
|
||||
for w in word_list:
|
||||
if w in after.name:
|
||||
name_filtered = True
|
||||
if after.nick and w in after.nick: # since Member.nick can be None
|
||||
nick_filtered = True
|
||||
if name_filtered and nick_filtered: # Both true, so break from loop
|
||||
break
|
||||
|
||||
if name_filtered and after.nick is None:
|
||||
try:
|
||||
await after.edit(nick=name_to_use, reason="Filtered name")
|
||||
except:
|
||||
pass
|
||||
elif nick_filtered:
|
||||
try:
|
||||
await after.edit(nick=None, reason="Filtered nickname")
|
||||
except:
|
||||
pass
|
||||
if before.display_name != after.display_name:
|
||||
await self.maybe_filter_name(after)
|
||||
|
||||
async def on_member_join(self, member: discord.Member):
|
||||
guild = member.guild
|
||||
if not guild.me.guild_permissions.manage_nicknames:
|
||||
return
|
||||
word_list = await self.settings.guild(guild).filter()
|
||||
filter_names = await self.settings.guild(guild).filter_names()
|
||||
name_to_use = await self.settings.guild(guild).filter_default_name()
|
||||
await self.maybe_filter_name(member)
|
||||
|
||||
if not filter_names:
|
||||
async def maybe_filter_name(self, member: discord.Member):
|
||||
if not member.guild.me.guild_permissions.manage_nicknames:
|
||||
return # No permissions to manage nicknames, so can't do anything
|
||||
if member.top_role >= member.guild.me.top_role:
|
||||
return # Discord Hierarchy applies to nicks
|
||||
if await self.bot.is_automod_immune(member):
|
||||
return
|
||||
word_list = await self.settings.guild(member.guild).filter()
|
||||
if not await self.settings.guild(member.guild).filter_names():
|
||||
return
|
||||
|
||||
for w in word_list:
|
||||
if w in member.name:
|
||||
if w in member.display_name.lower():
|
||||
name_to_use = await self.settings.guild(member.guild).filter_default_name()
|
||||
reason = "Filtered nick" if member.nick else "Filtered name"
|
||||
try:
|
||||
await member.edit(nick=name_to_use, reason="Filtered name")
|
||||
except:
|
||||
await member.edit(nick=name_to_use, reason=reason)
|
||||
except discord.HTTPException:
|
||||
pass
|
||||
break
|
||||
return
|
||||
|
||||
@ -1501,6 +1501,9 @@ class Mod:
|
||||
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:
|
||||
deleted = await self.check_mention_spam(message)
|
||||
|
||||
@ -5,6 +5,7 @@ from collections import Counter
|
||||
from enum import Enum
|
||||
from importlib.machinery import ModuleSpec
|
||||
from pathlib import Path
|
||||
from typing import Union
|
||||
|
||||
import discord
|
||||
import sys
|
||||
@ -72,6 +73,7 @@ class RedBase(commands.GroupMixin, commands.bot.BotBase, RPCMixin):
|
||||
use_bot_color=False,
|
||||
fuzzy=False,
|
||||
disabled_commands=[],
|
||||
autoimmune_ids=[],
|
||||
)
|
||||
|
||||
self.db.register_user(embeds=None)
|
||||
@ -294,6 +296,41 @@ class RedBase(commands.GroupMixin, commands.bot.BotBase, RPCMixin):
|
||||
if pkg_name.startswith("redbot.cogs."):
|
||||
del sys.modules["redbot.cogs"].__dict__[name]
|
||||
|
||||
async def is_automod_immune(
|
||||
self, to_check: Union[discord.Message, commands.Context, discord.abc.User, discord.Role]
|
||||
) -> bool:
|
||||
"""
|
||||
Checks if the user, message, context, or role should be considered immune from automated
|
||||
moderation actions.
|
||||
|
||||
This will return ``False`` in direct messages.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
to_check : `discord.Message` or `commands.Context` or `discord.abc.User` or `discord.Role`
|
||||
Something to check if it would be immune
|
||||
|
||||
Returns
|
||||
-------
|
||||
bool
|
||||
``True`` if immune
|
||||
|
||||
"""
|
||||
guild = to_check.guild
|
||||
if not guild:
|
||||
return False
|
||||
|
||||
if isinstance(to_check, discord.Role):
|
||||
ids_to_check = [to_check.id]
|
||||
else:
|
||||
author = getattr(to_check, "author", to_check)
|
||||
ids_to_check = [r.id for r in author.roles]
|
||||
ids_to_check.append(author.id)
|
||||
|
||||
immune_ids = await self.db.guild(guild).autoimmune_ids()
|
||||
|
||||
return any(i in immune_ids for i in ids_to_check)
|
||||
|
||||
@staticmethod
|
||||
async def send_filtered(
|
||||
destination: discord.abc.Messageable,
|
||||
|
||||
@ -14,7 +14,7 @@ from pathlib import Path
|
||||
from random import SystemRandom
|
||||
from string import ascii_letters, digits
|
||||
from distutils.version import StrictVersion
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import TYPE_CHECKING, Union
|
||||
|
||||
import aiohttp
|
||||
import discord
|
||||
@ -1694,6 +1694,82 @@ class Core(CoreLogic):
|
||||
await ctx.bot.db.disabled_command_msg.set(message)
|
||||
await ctx.tick()
|
||||
|
||||
@commands.guild_only()
|
||||
@checks.guildowner_or_permissions(manage_server=True)
|
||||
@commands.group(name="autoimmune")
|
||||
async def autoimmune_group(self, ctx: commands.Context):
|
||||
"""
|
||||
Server settings for immunity from automated actions
|
||||
"""
|
||||
pass
|
||||
|
||||
@autoimmune_group.command(name="list")
|
||||
async def autoimmune_list(self, ctx: commands.Context):
|
||||
"""
|
||||
Get's the current members and roles
|
||||
|
||||
configured for automatic moderation action immunity
|
||||
"""
|
||||
ai_ids = await ctx.bot.db.guild(ctx.guild).autoimmune_ids()
|
||||
|
||||
roles = {r.name for r in ctx.guild.roles if r.id in ai_ids}
|
||||
members = {str(m) for m in ctx.guild.members if m.id in ai_ids}
|
||||
|
||||
output = ""
|
||||
if roles:
|
||||
output += _("Roles immune from automated moderation actions:\n")
|
||||
output += ", ".join(roles)
|
||||
if members:
|
||||
if roles:
|
||||
output += "\n"
|
||||
output += _("Members immune from automated moderation actions:\n")
|
||||
output += ", ".join(members)
|
||||
|
||||
if not output:
|
||||
output = _("No immunty settings here.")
|
||||
|
||||
for page in pagify(output):
|
||||
await ctx.send(page)
|
||||
|
||||
@autoimmune_group.command(name="add")
|
||||
async def autoimmune_add(
|
||||
self, ctx: commands.Context, user_or_role: Union[discord.Member, discord.Role]
|
||||
):
|
||||
"""
|
||||
Makes a user or roles immune from automated moderation actions
|
||||
"""
|
||||
async with ctx.bot.db.guild(ctx.guild).autoimmune_ids() as ai_ids:
|
||||
if user_or_role.id in ai_ids:
|
||||
return await ctx.send(_("Already added."))
|
||||
ai_ids.append(user_or_role.id)
|
||||
await ctx.tick()
|
||||
|
||||
@autoimmune_group.command(name="remove")
|
||||
async def autoimmune_remove(
|
||||
self, ctx: commands.Context, user_or_role: Union[discord.Member, discord.Role]
|
||||
):
|
||||
"""
|
||||
Makes a user or roles immune from automated moderation actions
|
||||
"""
|
||||
async with ctx.bot.db.guild(ctx.guild).autoimmune_ids() as ai_ids:
|
||||
if user_or_role.id not in ai_ids:
|
||||
return await ctx.send(_("Not in list."))
|
||||
ai_ids.remove(user_or_role.id)
|
||||
await ctx.tick()
|
||||
|
||||
@autoimmune_group.command(name="isimmune")
|
||||
async def autoimmune_checkimmune(
|
||||
self, ctx: commands.Context, user_or_role: Union[discord.Member, discord.Role]
|
||||
):
|
||||
"""
|
||||
Checks if a user or role would be considered immune from automated actions
|
||||
"""
|
||||
|
||||
if await ctx.bot.is_automod_immune(user_or_role):
|
||||
await ctx.send(_("They are immune"))
|
||||
else:
|
||||
await ctx.send(_("They are not Immune"))
|
||||
|
||||
# RPC handlers
|
||||
async def rpc_load(self, request):
|
||||
cog_name = request.params[0]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user