[Mod] Move ignored guilds and channels to core (#3472)

* Move ignored guilds and channels to core
Add caching for ignored guilds and channels
Add caching for whitelist and blacklist
Fix #3220
Add consume-rest for whitelist and blacklist commands to add multiple users or roles in one command

* Add ability to ignore channel categories

* black

* moveignorechannels should be owner only and cleanup changes

* add changelog entries

* address Feedback
This commit is contained in:
TrustyJAID 2020-02-14 23:21:09 -07:00 committed by GitHub
parent 78192dc1af
commit 74a3eba08f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 457 additions and 238 deletions

View File

@ -0,0 +1,4 @@
Add caching for ignored channels/guilds.
Add caching for white/blacklist.
Add consume-rest for white/blacklist commands.
Allow ignoring channel categories.

View File

@ -0,0 +1 @@
Move ignore commands and checks into core.

View File

@ -17,7 +17,7 @@ from .settings import ModSettings
_ = T_ = Translator("Mod", __file__) _ = T_ = Translator("Mod", __file__)
__version__ = "1.0.0" __version__ = "1.1.0"
class CompositeMetaClass(type(commands.Cog), type(ABC)): class CompositeMetaClass(type(commands.Cog), type(ABC)):
@ -85,35 +85,36 @@ class Mod(
async def _maybe_update_config(self): async def _maybe_update_config(self):
"""Maybe update `delete_delay` value set by Config prior to Mod 1.0.0.""" """Maybe update `delete_delay` value set by Config prior to Mod 1.0.0."""
if await self.settings.version(): if not await self.settings.version():
return guild_dict = await self.settings.all_guilds()
guild_dict = await self.settings.all_guilds() for guild_id, info in guild_dict.items():
for guild_id, info in guild_dict.items(): delete_repeats = info.get("delete_repeats", False)
delete_repeats = info.get("delete_repeats", False) if delete_repeats:
if delete_repeats: val = 3
val = 3 else:
else: val = -1
val = -1 await self.settings.guild(discord.Object(id=guild_id)).delete_repeats.set(val)
await self.settings.guild(discord.Object(id=guild_id)).delete_repeats.set(val) await self.settings.version.set("1.0.0") # set version of last update
await self.settings.version.set(__version__) if await self.settings.version() < "1.1.0":
prefixes = await self.bot.get_valid_prefixes()
msg = _(
"Ignored guilds and channels have been moved. "
"Please use `{prefix}moveignoredchannels` if "
"you were previously using these functions."
).format(prefix=prefixes[0])
await self.bot.send_to_owners(msg)
await self.settings.version.set(__version__)
# TODO: Move this to core. @commands.command()
# This would be in .movetocore , but the double-under name here makes that more trouble @commands.is_owner()
async def bot_check(self, ctx): async def moveignoredchannels(self, ctx: commands.Context) -> None:
"""Global check to see if a channel or server is ignored. """Move ignored channels and servers to core"""
all_guilds = await self.settings.all_guilds()
Any users who have permission to use the `ignore` or `unignore` commands all_channels = await self.settings.all_channels()
surpass the check. for guild_id, settings in all_guilds.items():
""" await self.bot._config.guild_from_id(guild_id).ignored.set(settings["ignored"])
perms = ctx.channel.permissions_for(ctx.author) await self.settings.guild_from_id(guild_id).ignored.clear()
surpass_ignore = ( for channel_id, settings in all_channels.items():
isinstance(ctx.channel, discord.abc.PrivateChannel) await self.bot._config.channel_from_id(channel_id).ignored.set(settings["ignored"])
or perms.manage_guild await self.settings.channel_fro_id(channel_id).clear()
or await ctx.bot.is_owner(ctx.author) await ctx.send(_("Ignored channels and guilds restored."))
or await ctx.bot.is_admin(ctx.author)
)
if surpass_ignore:
return True
guild_ignored = await self.settings.guild(ctx.guild).ignored()
chann_ignored = await self.settings.channel(ctx.channel).ignored()
return not (guild_ignored or chann_ignored and not perms.manage_channels)

View File

@ -47,84 +47,3 @@ class MoveToCore(MixinMeta):
await asyncio.sleep(delay) await asyncio.sleep(delay)
await _delete_helper(message) await _delete_helper(message)
# When the below are moved to core, the global check in .modcore needs to be moved as well.
@commands.group()
@commands.guild_only()
@checks.admin_or_permissions(manage_channels=True)
async def ignore(self, ctx: commands.Context):
"""Add servers or channels to the ignore list."""
if ctx.invoked_subcommand is None:
await ctx.send(await self.count_ignored())
@ignore.command(name="channel")
async def ignore_channel(self, ctx: commands.Context, channel: discord.TextChannel = None):
"""Ignore commands in the channel.
Defaults to the current channel.
"""
if not channel:
channel = ctx.channel
if not await self.settings.channel(channel).ignored():
await self.settings.channel(channel).ignored.set(True)
await ctx.send(_("Channel added to ignore list."))
else:
await ctx.send(_("Channel already in ignore list."))
@ignore.command(name="server", aliases=["guild"])
@checks.admin_or_permissions(manage_guild=True)
async def ignore_guild(self, ctx: commands.Context):
"""Ignore commands in this server."""
guild = ctx.guild
if not await self.settings.guild(guild).ignored():
await self.settings.guild(guild).ignored.set(True)
await ctx.send(_("This server has been added to the ignore list."))
else:
await ctx.send(_("This server is already being ignored."))
@commands.group()
@commands.guild_only()
@checks.admin_or_permissions(manage_channels=True)
async def unignore(self, ctx: commands.Context):
"""Remove servers or channels from the ignore list."""
if ctx.invoked_subcommand is None:
await ctx.send(await self.count_ignored())
@unignore.command(name="channel")
async def unignore_channel(self, ctx: commands.Context, channel: discord.TextChannel = None):
"""Remove a channel from ignore the list.
Defaults to the current channel.
"""
if not channel:
channel = ctx.channel
if await self.settings.channel(channel).ignored():
await self.settings.channel(channel).ignored.set(False)
await ctx.send(_("Channel removed from ignore list."))
else:
await ctx.send(_("That channel is not in the ignore list."))
@unignore.command(name="server", aliases=["guild"])
@checks.admin_or_permissions(manage_guild=True)
async def unignore_guild(self, ctx: commands.Context):
"""Remove this server from the ignore list."""
guild = ctx.message.guild
if await self.settings.guild(guild).ignored():
await self.settings.guild(guild).ignored.set(False)
await ctx.send(_("This server has been removed from the ignore list."))
else:
await ctx.send(_("This server is not in the ignore list."))
async def count_ignored(self):
ch_count = 0
svr_count = 0
for guild in self.bot.guilds:
if not await self.settings.guild(guild).ignored():
for channel in guild.text_channels:
if await self.settings.channel(channel).ignored():
ch_count += 1
else:
svr_count += 1
msg = _("Currently ignoring:\n{} channels\n{} guilds\n").format(ch_count, svr_count)
return box(msg)

View File

@ -38,7 +38,7 @@ from .dev_commands import Dev
from .events import init_events from .events import init_events
from .global_checks import init_global_checks from .global_checks import init_global_checks
from .settings_caches import PrefixManager from .settings_caches import PrefixManager, IgnoreManager, WhitelistBlacklistManager
from .rpc import RPCMixin from .rpc import RPCMixin
from .utils import common_filters from .utils import common_filters
@ -118,13 +118,14 @@ class RedBase(
admin_role=[], admin_role=[],
mod_role=[], mod_role=[],
embeds=None, embeds=None,
ignored=False,
use_bot_color=False, use_bot_color=False,
fuzzy=False, fuzzy=False,
disabled_commands=[], disabled_commands=[],
autoimmune_ids=[], autoimmune_ids=[],
) )
self._config.register_channel(embeds=None) self._config.register_channel(embeds=None, ignored=False)
self._config.register_user(embeds=None) self._config.register_user(embeds=None)
self._config.init_custom(CUSTOM_GROUPS, 2) self._config.init_custom(CUSTOM_GROUPS, 2)
@ -133,6 +134,8 @@ class RedBase(
self._config.init_custom(SHARED_API_TOKENS, 2) self._config.init_custom(SHARED_API_TOKENS, 2)
self._config.register_custom(SHARED_API_TOKENS) self._config.register_custom(SHARED_API_TOKENS)
self._prefix_cache = PrefixManager(self._config, cli_flags) self._prefix_cache = PrefixManager(self._config, cli_flags)
self._ignored_cache = IgnoreManager(self._config)
self._whiteblacklist_cache = WhitelistBlacklistManager(self._config)
async def prefix_manager(bot, message) -> List[str]: async def prefix_manager(bot, message) -> List[str]:
prefixes = await self._prefix_cache.get_prefixes(message.guild) prefixes = await self._prefix_cache.get_prefixes(message.guild)
@ -350,13 +353,13 @@ class RedBase(
if await self.is_owner(who): if await self.is_owner(who):
return True return True
global_whitelist = await self._config.whitelist() global_whitelist = await self._whiteblacklist_cache.get_whitelist()
if global_whitelist: if global_whitelist:
if who.id not in global_whitelist: if who.id not in global_whitelist:
return False return False
else: else:
# blacklist is only used when whitelist doesn't exist. # blacklist is only used when whitelist doesn't exist.
global_blacklist = await self._config.blacklist() global_blacklist = await self._whiteblacklist_cache.get_blacklist()
if who.id in global_blacklist: if who.id in global_blacklist:
return False return False
@ -375,17 +378,44 @@ class RedBase(
# there is a silent failure potential, and role blacklist/whitelists will break. # there is a silent failure potential, and role blacklist/whitelists will break.
ids = {i for i in (who.id, *(getattr(who, "_roles", []))) if i != guild.id} ids = {i for i in (who.id, *(getattr(who, "_roles", []))) if i != guild.id}
guild_whitelist = await self._config.guild(guild).whitelist() guild_whitelist = await self._whiteblacklist_cache.get_whitelist(guild)
if guild_whitelist: if guild_whitelist:
if ids.isdisjoint(guild_whitelist): if ids.isdisjoint(guild_whitelist):
return False return False
else: else:
guild_blacklist = await self._config.guild(guild).blacklist() guild_blacklist = await self._whiteblacklist_cache.get_blacklist(guild)
if not ids.isdisjoint(guild_blacklist): if not ids.isdisjoint(guild_blacklist):
return False return False
return True return True
async def ignored_channel_or_guild(self, ctx: commands.Context) -> bool:
"""
This checks if the bot is meant to be ignoring commands in a channel or guild,
as considered by Red's whitelist and blacklist.
Parameters
----------
ctx : Context of where the command is being run.
Returns
-------
bool
`True` if commands are allowed in the channel, `False` otherwise
"""
perms = ctx.channel.permissions_for(ctx.author)
surpass_ignore = (
isinstance(ctx.channel, discord.abc.PrivateChannel)
or perms.manage_guild
or await ctx.bot.is_owner(ctx.author)
or await ctx.bot.is_admin(ctx.author)
)
if surpass_ignore:
return True
guild_ignored = await self._ignored_cache.get_ignored_guild(ctx.guild)
chann_ignored = await self._ignored_cache.get_ignored_channel(ctx.channel)
return not (guild_ignored or chann_ignored and not perms.manage_channels)
async def get_valid_prefixes(self, guild: Optional[discord.Guild] = None) -> List[str]: async def get_valid_prefixes(self, guild: Optional[discord.Guild] = None) -> List[str]:
""" """
This gets the valid prefixes for a guild. This gets the valid prefixes for a guild.

View File

@ -1702,16 +1702,14 @@ class Core(commands.Cog, CoreLogic):
pass pass
@whitelist.command(name="add") @whitelist.command(name="add")
async def whitelist_add(self, ctx, *, user: Union[discord.Member, int]): async def whitelist_add(self, ctx: commands.Context, *users: List[Union[discord.Member, int]]):
""" """
Adds a user to the whitelist. Adds a user to the whitelist.
""" """
uid = getattr(user, "id", user) uids = [getattr(user, "id", user) for user in users]
async with ctx.bot._config.whitelist() as curr_list: await self.bot._whiteblacklist_cache.add_to_whitelist(None, uids)
if uid not in curr_list:
curr_list.append(uid)
await ctx.send(_("User added to whitelist.")) await ctx.send(_("Users added to whitelist."))
@whitelist.command(name="list") @whitelist.command(name="list")
async def whitelist_list(self, ctx: commands.Context): async def whitelist_list(self, ctx: commands.Context):
@ -1732,28 +1730,23 @@ class Core(commands.Cog, CoreLogic):
await ctx.send(box(page)) await ctx.send(box(page))
@whitelist.command(name="remove") @whitelist.command(name="remove")
async def whitelist_remove(self, ctx: commands.Context, *, user: Union[discord.Member, int]): async def whitelist_remove(
self, ctx: commands.Context, *users: List[Union[discord.Member, int]]
):
""" """
Removes user from whitelist. Removes user from whitelist.
""" """
removed = False uids = [getattr(user, "id", user) for user in users]
uid = getattr(user, "id", user) await self.bot._whiteblacklist_cache.remove_from_whitelist(None, uids)
async with ctx.bot._config.whitelist() as curr_list:
if uid in curr_list:
removed = True
curr_list.remove(uid)
if removed: await ctx.send(_("Users have been removed from whitelist."))
await ctx.send(_("User has been removed from whitelist."))
else:
await ctx.send(_("User was not in the whitelist."))
@whitelist.command(name="clear") @whitelist.command(name="clear")
async def whitelist_clear(self, ctx: commands.Context): async def whitelist_clear(self, ctx: commands.Context):
""" """
Clears the whitelist. Clears the whitelist.
""" """
await ctx.bot._config.whitelist.set([]) await self.bot._whiteblacklist_cache.clear_whitelist()
await ctx.send(_("Whitelist has been cleared.")) await ctx.send(_("Whitelist has been cleared."))
@commands.group() @commands.group()
@ -1765,18 +1758,21 @@ class Core(commands.Cog, CoreLogic):
pass pass
@blacklist.command(name="add") @blacklist.command(name="add")
async def blacklist_add(self, ctx: commands.Context, *, user: Union[discord.Member, int]): async def blacklist_add(self, ctx: commands.Context, *users: List[Union[discord.Member, int]]):
""" """
Adds a user to the blacklist. Adds a user to the blacklist.
""" """
if await ctx.bot.is_owner(user): for user in users:
await ctx.send(_("You cannot blacklist an owner!")) if isinstance(user, int):
return user_obj = discord.Object(id=user)
else:
user_obj = user
if await ctx.bot.is_owner(user_obj):
await ctx.send(_("You cannot blacklist an owner!"))
return
uid = getattr(user, "id", user) uids = [getattr(user, "id", user) for user in users]
async with ctx.bot._config.blacklist() as curr_list: await self.bot._whiteblacklist_cache.add_to_blacklist(None, uids)
if uid not in curr_list:
curr_list.append(uid)
await ctx.send(_("User added to blacklist.")) await ctx.send(_("User added to blacklist."))
@ -1785,7 +1781,7 @@ class Core(commands.Cog, CoreLogic):
""" """
Lists blacklisted users. Lists blacklisted users.
""" """
curr_list = await ctx.bot._config.blacklist() curr_list = await self.bot._whiteblacklist_cache.get_blacklist(None)
if not curr_list: if not curr_list:
await ctx.send("Blacklist is empty.") await ctx.send("Blacklist is empty.")
@ -1799,29 +1795,24 @@ class Core(commands.Cog, CoreLogic):
await ctx.send(box(page)) await ctx.send(box(page))
@blacklist.command(name="remove") @blacklist.command(name="remove")
async def blacklist_remove(self, ctx: commands.Context, *, user: Union[discord.Member, int]): async def blacklist_remove(
self, ctx: commands.Context, *users: List[Union[discord.Member, int]]
):
""" """
Removes user from blacklist. Removes user from blacklist.
""" """
removed = False
uid = getattr(user, "id", user) uids = [getattr(user, "id", user) for user in users]
async with ctx.bot._config.blacklist() as curr_list: await self.bot._whiteblacklist_cache.remove_from_blacklist(None, uids)
if uid in curr_list:
removed = True
curr_list.remove(uid)
if removed: await ctx.send(_("Users have been removed from blacklist."))
await ctx.send(_("User has been removed from blacklist."))
else:
await ctx.send(_("User was not in the blacklist."))
@blacklist.command(name="clear") @blacklist.command(name="clear")
async def blacklist_clear(self, ctx: commands.Context): async def blacklist_clear(self, ctx: commands.Context):
""" """
Clears the blacklist. Clears the blacklist.
""" """
await ctx.bot._config.blacklist.set([]) await self.bot._whiteblacklist_cache.clear_blacklist()
await ctx.send(_("Blacklist has been cleared.")) await ctx.send(_("Blacklist has been cleared."))
@commands.group() @commands.group()
@ -1835,31 +1826,25 @@ class Core(commands.Cog, CoreLogic):
@localwhitelist.command(name="add") @localwhitelist.command(name="add")
async def localwhitelist_add( async def localwhitelist_add(
self, ctx: commands.Context, *, user_or_role: Union[discord.Member, discord.Role, int] self,
ctx: commands.Context,
*users_or_roles: List[Union[discord.Member, discord.Role, int]],
): ):
""" """
Adds a user or role to the whitelist. Adds a user or role to the whitelist.
""" """
user = isinstance(user_or_role, discord.Member) names = [getattr(users_or_roles, "name", users_or_roles) for u_or_r in users_or_roles]
if isinstance(user_or_role, int): uids = [getattr(users_or_roles, "id", users_or_roles) for u_or_r in users_or_roles]
user_or_role = discord.Object(id=user_or_role) await self.bot._whiteblacklist_cache.add_to_whitelist(ctx.guild, uids)
user = True
async with ctx.bot._config.guild(ctx.guild).whitelist() as curr_list: await ctx.send(_("{names} added to whitelist.").format(names=humanize_list(names)))
if user_or_role.id not in curr_list:
curr_list.append(user_or_role.id)
if user:
await ctx.send(_("User added to whitelist."))
else:
await ctx.send(_("Role added to whitelist."))
@localwhitelist.command(name="list") @localwhitelist.command(name="list")
async def localwhitelist_list(self, ctx: commands.Context): async def localwhitelist_list(self, ctx: commands.Context):
""" """
Lists whitelisted users and roles. Lists whitelisted users and roles.
""" """
curr_list = await ctx.bot._config.guild(ctx.guild).whitelist() curr_list = await self.bot._whiteblacklist_cache.get_whitelist(ctx.guild)
if not curr_list: if not curr_list:
await ctx.send("Local whitelist is empty.") await ctx.send("Local whitelist is empty.")
@ -1874,40 +1859,28 @@ class Core(commands.Cog, CoreLogic):
@localwhitelist.command(name="remove") @localwhitelist.command(name="remove")
async def localwhitelist_remove( async def localwhitelist_remove(
self, ctx: commands.Context, *, user_or_role: Union[discord.Member, discord.Role, int] self,
ctx: commands.Context,
*users_or_roles: List[Union[discord.Member, discord.Role, int]],
): ):
""" """
Removes user or role from whitelist. Removes user or role from whitelist.
""" """
user = isinstance(user_or_role, discord.Member) names = [getattr(users_or_roles, "name", users_or_roles) for u_or_r in users_or_roles]
if isinstance(user_or_role, int): uids = [getattr(users_or_roles, "id", users_or_roles) for u_or_r in users_or_roles]
user_or_role = discord.Object(id=user_or_role) await self.bot._whiteblacklist_cache.remove_from_whitelist(ctx.guild, uids)
user = True
removed = False await ctx.send(
async with ctx.bot._config.guild(ctx.guild).whitelist() as curr_list: _("{names} removed from the local whitelist.").format(names=humanize_list(names))
if user_or_role.id in curr_list: )
removed = True
curr_list.remove(user_or_role.id)
if removed:
if user:
await ctx.send(_("User has been removed from whitelist."))
else:
await ctx.send(_("Role has been removed from whitelist."))
else:
if user:
await ctx.send(_("User was not in the whitelist."))
else:
await ctx.send(_("Role was not in the whitelist."))
@localwhitelist.command(name="clear") @localwhitelist.command(name="clear")
async def localwhitelist_clear(self, ctx: commands.Context): async def localwhitelist_clear(self, ctx: commands.Context):
""" """
Clears the whitelist. Clears the whitelist.
""" """
await ctx.bot._config.guild(ctx.guild).whitelist.set([]) await self.bot._whiteblacklist_cache.clear_whitelist(ctx.guild)
await ctx.send(_("Whitelist has been cleared.")) await ctx.send(_("Local whitelist has been cleared."))
@commands.group() @commands.group()
@commands.guild_only() @commands.guild_only()
@ -1920,42 +1893,38 @@ class Core(commands.Cog, CoreLogic):
@localblacklist.command(name="add") @localblacklist.command(name="add")
async def localblacklist_add( async def localblacklist_add(
self, ctx: commands.Context, *, user_or_role: Union[discord.Member, discord.Role, int] self,
ctx: commands.Context,
*users_or_roles: List[Union[discord.Member, discord.Role, int]],
): ):
""" """
Adds a user or role to the blacklist. Adds a user or role to the blacklist.
""" """
user = isinstance(user_or_role, discord.Member) for user_or_role in users_or_roles:
if isinstance(user_or_role, int): uid = discord.Object(id=getattr(user_or_role, "id", user_or_role))
user_or_role = discord.Object(id=user_or_role) if uid.id == ctx.author.id:
user = True
if user:
if user_or_role.id == ctx.author.id:
await ctx.send(_("You cannot blacklist yourself!")) await ctx.send(_("You cannot blacklist yourself!"))
return return
if user_or_role.id == ctx.guild.owner_id and not await ctx.bot.is_owner(ctx.author): if uid.id == ctx.guild.owner_id and not await ctx.bot.is_owner(ctx.author):
await ctx.send(_("You cannot blacklist the guild owner!")) await ctx.send(_("You cannot blacklist the guild owner!"))
return return
if await ctx.bot.is_owner(user_or_role): if await ctx.bot.is_owner(uid):
await ctx.send(_("You cannot blacklist a bot owner!")) await ctx.send(_("You cannot blacklist a bot owner!"))
return return
names = [getattr(users_or_roles, "name", users_or_roles) for u_or_r in users_or_roles]
uids = [getattr(users_or_roles, "id", users_or_roles) for u_or_r in users_or_roles]
await self.bot._whiteblacklist_cache.add_to_blacklist(ctx.guild, uids)
async with ctx.bot._config.guild(ctx.guild).blacklist() as curr_list: await ctx.send(
if user_or_role.id not in curr_list: _("{names} added to the local blacklist.").format(names=humanize_list(names))
curr_list.append(user_or_role.id) )
if user:
await ctx.send(_("User added to blacklist."))
else:
await ctx.send(_("Role added to blacklist."))
@localblacklist.command(name="list") @localblacklist.command(name="list")
async def localblacklist_list(self, ctx: commands.Context): async def localblacklist_list(self, ctx: commands.Context):
""" """
Lists blacklisted users and roles. Lists blacklisted users and roles.
""" """
curr_list = await ctx.bot._config.guild(ctx.guild).blacklist() curr_list = await self.bot._whiteblacklist_cache.get_blacklist(ctx.guild)
if not curr_list: if not curr_list:
await ctx.send("Local blacklist is empty.") await ctx.send("Local blacklist is empty.")
@ -1970,32 +1939,18 @@ class Core(commands.Cog, CoreLogic):
@localblacklist.command(name="remove") @localblacklist.command(name="remove")
async def localblacklist_remove( async def localblacklist_remove(
self, ctx: commands.Context, *, user_or_role: Union[discord.Member, discord.Role, int] self, ctx: commands.Context, *users_or_roles: Union[discord.Member, discord.Role, int]
): ):
""" """
Removes user or role from blacklist. Removes user or role from blacklist.
""" """
removed = False names = [getattr(users_or_roles, "name", users_or_roles) for u_or_r in users_or_roles]
user = isinstance(user_or_role, discord.Member) uids = [getattr(users_or_roles, "id", users_or_roles) for u_or_r in users_or_roles]
if isinstance(user_or_role, int): await self.bot._whiteblacklist_cache.remove_from_whitelist(ctx.guild, uids)
user_or_role = discord.Object(id=user_or_role)
user = True
async with ctx.bot._config.guild(ctx.guild).blacklist() as curr_list: await ctx.send(
if user_or_role.id in curr_list: _("{names} removed from the local blacklist.").format(names=humanize_list(names))
removed = True )
curr_list.remove(user_or_role.id)
if removed:
if user:
await ctx.send(_("User has been removed from blacklist."))
else:
await ctx.send(_("Role has been removed from blacklist."))
else:
if user:
await ctx.send(_("User was not in the blacklist."))
else:
await ctx.send(_("Role was not in the blacklist."))
@localblacklist.command(name="clear") @localblacklist.command(name="clear")
async def localblacklist_clear(self, ctx: commands.Context): async def localblacklist_clear(self, ctx: commands.Context):
@ -2003,7 +1958,7 @@ class Core(commands.Cog, CoreLogic):
Clears the blacklist. Clears the blacklist.
""" """
await ctx.bot._config.guild(ctx.guild).blacklist.set([]) await ctx.bot._config.guild(ctx.guild).blacklist.set([])
await ctx.send(_("Blacklist has been cleared.")) await ctx.send(_("Local blacklist has been cleared."))
@checks.guildowner_or_permissions(administrator=True) @checks.guildowner_or_permissions(administrator=True)
@commands.group(name="command") @commands.group(name="command")
@ -2409,6 +2364,107 @@ class Core(commands.Cog, CoreLogic):
await self.rpc_unload(request) await self.rpc_unload(request)
await self.rpc_load(request) await self.rpc_load(request)
@commands.group()
@commands.guild_only()
@checks.admin_or_permissions(manage_channels=True)
async def ignore(self, ctx: commands.Context):
"""Add servers or channels to the ignore list."""
if ctx.invoked_subcommand is None:
for page in pagify(await self.count_ignored(ctx)):
await ctx.maybe_send_embed(page)
@ignore.command(name="channel")
async def ignore_channel(
self,
ctx: commands.Context,
channel: Optional[Union[discord.TextChannel, discord.CategoryChannel]] = None,
):
"""Ignore commands in the channel or category.
Defaults to the current channel.
"""
if not channel:
channel = ctx.channel
if not await self.bot._ignored_cache.get_ignored_channel(channel):
await self.bot._ignored_cache.set_ignored_channel(channel, True)
await ctx.send(_("Channel added to ignore list."))
else:
await ctx.send(_("Channel already in ignore list."))
@ignore.command(name="server", aliases=["guild"])
@checks.admin_or_permissions(manage_guild=True)
async def ignore_guild(self, ctx: commands.Context):
"""Ignore commands in this server."""
guild = ctx.guild
if not await self.bot._ignored_cache.get_ignored_guild(guild):
await self.bot._ignored_cache.set_ignored_guild(guild, True)
await ctx.send(_("This server has been added to the ignore list."))
else:
await ctx.send(_("This server is already being ignored."))
@commands.group()
@commands.guild_only()
@checks.admin_or_permissions(manage_channels=True)
async def unignore(self, ctx: commands.Context):
"""Remove servers or channels from the ignore list."""
if ctx.invoked_subcommand is None:
for page in pagify(await self.count_ignored(ctx)):
await ctx.maybe_send_embed(page)
@unignore.command(name="channel")
async def unignore_channel(
self,
ctx: commands.Context,
channel: Optional[Union[discord.TextChannel, discord.CategoryChannel]] = None,
):
"""Remove a channel or category from ignore the list.
Defaults to the current channel.
"""
if not channel:
channel = ctx.channel
if await self.bot._ignored_cache.get_ignored_channel(channel):
await self.bot._ignored_cache.set_ignored_channel(channel, False)
await ctx.send(_("Channel removed from ignore list."))
else:
await ctx.send(_("That channel is not in the ignore list."))
@unignore.command(name="server", aliases=["guild"])
@checks.admin_or_permissions(manage_guild=True)
async def unignore_guild(self, ctx: commands.Context):
"""Remove this server from the ignore list."""
guild = ctx.message.guild
if await self.bot._ignored_cache.get_ignored_guild(guild):
await self.bot._ignored_cache.set_ignored_guild(guild, False)
await ctx.send(_("This server has been removed from the ignore list."))
else:
await ctx.send(_("This server is not in the ignore list."))
async def count_ignored(self, ctx: commands.Context):
category_channels: List[discord.CategoryChannel] = []
text_channels: List[discord.TextChannel] = []
if await self.bot._ignored_cache.get_ignored_guild(ctx.guild):
return _("This server is currently being ignored.")
for channel in ctx.guild.text_channels:
if channel.category and channel.category not in category_channels:
if await self.bot._ignored_cache.get_ignored_channel(channel.category):
category_channels.append(channel.category)
continue
else:
continue
if await self.bot._ignored_cache.get_ignored_channel(channel):
text_channels.append(channel)
cat_str = (
humanize_list([c.name for c in category_channels]) if category_channels else "None"
)
chan_str = humanize_list([c.mention for c in text_channels]) if text_channels else "None"
msg = _("Currently ignored categories: {categories}\nChannels:{channels}").format(
categories=cat_str, channels=chan_str
)
return msg
# Removing this command from forks is a violation of the GPLv3 under which it is licensed. # Removing this command from forks is a violation of the GPLv3 under which it is licensed.
# Otherwise interfering with the ability for this command to be accessible is also a violation. # Otherwise interfering with the ability for this command to be accessible is also a violation.

View File

@ -7,7 +7,7 @@ def init_global_checks(bot):
def minimum_bot_perms(ctx) -> bool: def minimum_bot_perms(ctx) -> bool:
""" """
Too many 403, 401, and 429 Errors can cause bots to get global'd Too many 403, 401, and 429 Errors can cause bots to get global'd
It's reasonable to assume the below as a minimum amount of perms for It's reasonable to assume the below as a minimum amount of perms for
commands. commands.
""" """
@ -17,6 +17,11 @@ def init_global_checks(bot):
async def whiteblacklist_checks(ctx) -> bool: async def whiteblacklist_checks(ctx) -> bool:
return await ctx.bot.allowed_by_whitelist_blacklist(ctx.author) return await ctx.bot.allowed_by_whitelist_blacklist(ctx.author)
@bot.check_once
async def ignore_checks(ctx) -> bool:
"""Check the channel or server is not ignored"""
return await ctx.bot.ignored_channel_or_guild(ctx)
@bot.check_once @bot.check_once
def bots(ctx) -> bool: def bots(ctx) -> bool:
"""Check the user is not another bot.""" """Check the user is not another bot."""

View File

@ -1,6 +1,6 @@
from __future__ import annotations from __future__ import annotations
from typing import Dict, List, Optional from typing import Dict, List, Optional, Union
from argparse import Namespace from argparse import Namespace
import discord import discord
@ -51,3 +51,206 @@ class PrefixManager:
else: else:
del self._cached[gid] del self._cached[gid]
await self._config.guild_from_id(gid).prefix.set(prefixes) await self._config.guild_from_id(gid).prefix.set(prefixes)
class IgnoreManager:
def __init__(self, config: Config):
self._config: Config = config
self._cached_channels: Dict[int, bool] = {}
self._cached_guilds: Dict[int, bool] = {}
async def get_ignored_channel(self, channel: discord.TextChannel) -> bool:
ret: bool
cid: int = channel.id
cat_id: Optional[int] = channel.category.id if channel.category else None
if cid in self._cached_channels:
chan_ret = self._cached_channels[cid]
else:
chan_ret = await self._config.channel_from_id(cid).ignored()
self._cached_channels[cid] = chan_ret
if cat_id and cat_id in self._cached_channels:
cat_ret = self._cached_channels[cat_id]
else:
if cat_id:
cat_ret = await self._config.channel_from_id(cat_id).ignored()
self._cached_channels[cat_id] = cat_ret
else:
cat_ret = False
ret = chan_ret or cat_ret
return ret
async def set_ignored_channel(
self, channel: Union[discord.TextChannel, discord.CategoryChannel], set_to: bool
):
cid: int = channel.id
self._cached_channels[cid] = set_to
if set_to:
await self._config.channel_from_id(cid).ignored.set(set_to)
else:
await self._config.channel_from_id(cid).ignored.clear()
async def get_ignored_guild(self, guild: discord.Guild) -> bool:
ret: bool
gid: int = guild.id
if gid in self._cached_guilds:
ret = self._cached_guilds[gid]
else:
ret = await self._config.guild_from_id(gid).ignored()
self._cached_guilds[gid] = ret
return ret
async def set_ignored_guild(self, guild: discord.Guild, set_to: bool):
gid: int = guild.id
self._cached_guilds[gid] = set_to
if set_to:
await self._config.guild_from_id(gid).ignored.set(set_to)
else:
await self._config.guild_from_id(gid).ignored.clear()
class WhitelistBlacklistManager:
def __init__(self, config: Config):
self._config: Config = config
self._cached_whitelist: Dict[Optional[int], List[int]] = {}
self._cached_blacklist: Dict[Optional[int], List[int]] = {}
async def get_whitelist(self, guild: Optional[discord.Guild] = None) -> List[int]:
ret: List[int]
gid: Optional[int] = guild.id if guild else None
if gid in self._cached_whitelist:
ret = self._cached_whitelist[gid].copy()
else:
if gid is not None:
ret = await self._config.guild_from_id(gid).whitelsit()
if not ret:
ret = []
else:
ret = await self._config.whitelist()
self._cached_whitelist[gid] = ret.copy()
return ret
async def add_to_whitelist(self, guild: Optional[discord.Guild], role_or_user: List[int]):
gid: Optional[int] = guild.id if guild else None
role_or_user = role_or_user or []
if not isinstance(role_or_user, list) and not all(
isinstance(r_or_u, str) for r_or_u in role_or_user
):
raise TypeError("Whitelisted objects must be a list of ints")
if gid is None:
for obj_id in role_or_user:
if obj_id not in self._cached_whitelist:
self._cached_whitelist[gid].append(obj_id)
async with self._config.whitelist() as curr_list:
curr_list.append(obj_id)
else:
for obj_id in role_or_user:
if obj_id not in self._cached_whitelist:
self._cached_whitelist[gid].append(obj_id)
async with self._config.guild_from_id(gid).whitelist() as curr_list:
curr_list.append(obj_id)
async def clear_whitelist(self, guild: Optional[discord.Guild] = None):
gid: Optional[int] = guild.id if guild else None
self._cached_whitelist[gid]
if gid is None:
await self._config.whitelist.clear()
else:
await self._config.guild_from_id(gid).whitelist.clear()
async def remove_from_whitelist(self, guild: Optional[discord.Guild], role_or_user: List[int]):
gid: Optional[int] = guild.id if guild else None
role_or_user = role_or_user or []
if not isinstance(role_or_user, list) and not all(
isinstance(r_or_u, str) for r_or_u in role_or_user
):
raise TypeError("Whitelisted objects must be a list of ints")
if gid is None:
for obj_id in role_or_user:
if obj_id in self._cached_whitelist:
self._cached_whitelist[gid].remove(obj_id)
async with self._config.whitelist() as curr_list:
curr_list.remove(obj_id)
else:
for obj_id in role_or_user:
if obj_id not in self._cached_whitelist:
self._cached_whitelist[gid].remove(obj_id)
async with self._config.guild_from_id(gid).whitelist() as curr_list:
curr_list.remove(obj_id)
async def get_blacklist(self, guild: Optional[discord.Guild] = None) -> List[int]:
ret: List[int]
gid: Optional[int] = guild.id if guild else None
if gid in self._cached_blacklist:
ret = self._cached_blacklist[gid].copy()
else:
if gid is not None:
ret = await self._config.guild_from_id(gid).whitelsit()
if not ret:
ret = []
else:
ret = await self._config.blacklist()
self._cached_blacklist[gid] = ret.copy()
return ret
async def add_to_blacklist(self, guild: Optional[discord.Guild], role_or_user: List[int]):
gid: Optional[int] = guild.id if guild else None
role_or_user = role_or_user or []
if not isinstance(role_or_user, list) and not all(
isinstance(r_or_u, str) for r_or_u in role_or_user
):
raise TypeError("Blacklisted objects must be a list of ints")
if gid is None:
for obj_id in role_or_user:
if obj_id not in self._cached_blacklist:
self._cached_blacklist[gid].append(obj_id)
async with self._config.blacklist() as curr_list:
curr_list.append(obj_id)
else:
for obj_id in role_or_user:
if obj_id not in self._cached_blacklist:
self._cached_blacklist[gid].append(obj_id)
async with self._config.guild_from_id(gid).blacklist() as curr_list:
curr_list.append(obj_id)
async def clear_blacklist(self, guild: Optional[discord.Guild] = None):
gid: Optional[int] = guild.id if guild else None
self._cached_whitelist[gid]
if gid is None:
await self._config.blacklist.clear()
else:
await self._config.guild_from_id(gid).blacklist.clear()
async def remove_from_blacklist(self, guild: Optional[discord.Guild], role_or_user: List[int]):
gid: Optional[int] = guild.id if guild else None
role_or_user = role_or_user or []
if not isinstance(role_or_user, list) and not all(
isinstance(r_or_u, str) for r_or_u in role_or_user
):
raise TypeError("Blacklisted objects must be a list of ints")
if gid is None:
for obj_id in role_or_user:
if obj_id in self._cached_blacklist:
self._cached_blacklist[gid].remove(obj_id)
async with self._config.blacklist() as curr_list:
curr_list.remove(obj_id)
else:
for obj_id in role_or_user:
if obj_id not in self._cached_blacklist:
self._cached_blacklist[gid].remove(obj_id)
async with self._config.guild_from_id(gid).blacklist() as curr_list:
curr_list.remove(obj_id)