mirror of
https://github.com/Cog-Creators/Red-DiscordBot.git
synced 2025-11-06 11:18:54 -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)
|
mod_or_superior = await is_mod_or_superior(self.bot, obj=author)
|
||||||
if mod_or_superior:
|
if mod_or_superior:
|
||||||
return
|
return
|
||||||
|
# As is anyone configured to be
|
||||||
await self.check_filter(message)
|
if await self.bot.is_automod_immune(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:
|
|
||||||
return
|
return
|
||||||
|
|
||||||
await self.check_filter(message)
|
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):
|
async def on_member_update(self, before: discord.Member, after: discord.Member):
|
||||||
if not after.guild.me.guild_permissions.manage_nicknames:
|
if before.display_name != after.display_name:
|
||||||
return # No permissions to manage nicknames, so can't do anything
|
await self.maybe_filter_name(after)
|
||||||
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
|
|
||||||
|
|
||||||
async def on_member_join(self, member: discord.Member):
|
async def on_member_join(self, member: discord.Member):
|
||||||
guild = member.guild
|
await self.maybe_filter_name(member)
|
||||||
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()
|
|
||||||
|
|
||||||
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
|
return
|
||||||
|
|
||||||
for w in word_list:
|
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:
|
try:
|
||||||
await member.edit(nick=name_to_use, reason="Filtered name")
|
await member.edit(nick=name_to_use, reason=reason)
|
||||||
except:
|
except discord.HTTPException:
|
||||||
pass
|
pass
|
||||||
break
|
return
|
||||||
|
|||||||
@ -1501,6 +1501,9 @@ class Mod:
|
|||||||
mod_or_superior = await is_mod_or_superior(self.bot, obj=author)
|
mod_or_superior = await is_mod_or_superior(self.bot, obj=author)
|
||||||
if mod_or_superior:
|
if mod_or_superior:
|
||||||
return
|
return
|
||||||
|
# As are anyone configured to be
|
||||||
|
if await self.bot.is_automod_immune(message):
|
||||||
|
return
|
||||||
deleted = await self.check_duplicates(message)
|
deleted = await self.check_duplicates(message)
|
||||||
if not deleted:
|
if not deleted:
|
||||||
deleted = await self.check_mention_spam(message)
|
deleted = await self.check_mention_spam(message)
|
||||||
|
|||||||
@ -5,6 +5,7 @@ from collections import Counter
|
|||||||
from enum import Enum
|
from enum import Enum
|
||||||
from importlib.machinery import ModuleSpec
|
from importlib.machinery import ModuleSpec
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
import discord
|
import discord
|
||||||
import sys
|
import sys
|
||||||
@ -72,6 +73,7 @@ class RedBase(commands.GroupMixin, commands.bot.BotBase, RPCMixin):
|
|||||||
use_bot_color=False,
|
use_bot_color=False,
|
||||||
fuzzy=False,
|
fuzzy=False,
|
||||||
disabled_commands=[],
|
disabled_commands=[],
|
||||||
|
autoimmune_ids=[],
|
||||||
)
|
)
|
||||||
|
|
||||||
self.db.register_user(embeds=None)
|
self.db.register_user(embeds=None)
|
||||||
@ -294,6 +296,41 @@ class RedBase(commands.GroupMixin, commands.bot.BotBase, RPCMixin):
|
|||||||
if pkg_name.startswith("redbot.cogs."):
|
if pkg_name.startswith("redbot.cogs."):
|
||||||
del sys.modules["redbot.cogs"].__dict__[name]
|
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
|
@staticmethod
|
||||||
async def send_filtered(
|
async def send_filtered(
|
||||||
destination: discord.abc.Messageable,
|
destination: discord.abc.Messageable,
|
||||||
|
|||||||
@ -14,7 +14,7 @@ from pathlib import Path
|
|||||||
from random import SystemRandom
|
from random import SystemRandom
|
||||||
from string import ascii_letters, digits
|
from string import ascii_letters, digits
|
||||||
from distutils.version import StrictVersion
|
from distutils.version import StrictVersion
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING, Union
|
||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
import discord
|
import discord
|
||||||
@ -1694,6 +1694,82 @@ class Core(CoreLogic):
|
|||||||
await ctx.bot.db.disabled_command_msg.set(message)
|
await ctx.bot.db.disabled_command_msg.set(message)
|
||||||
await ctx.tick()
|
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
|
# RPC handlers
|
||||||
async def rpc_load(self, request):
|
async def rpc_load(self, request):
|
||||||
cog_name = request.params[0]
|
cog_name = request.params[0]
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user