mirror of
https://github.com/Cog-Creators/Red-DiscordBot.git
synced 2025-11-08 12:18:54 -05:00
More privatization, and some error helpers (#2976)
* More privatization, and some error helpers This makes a lot more things private. Continued from #2967, fixes #2984 Adds public methods for various things. Below is a brief summary of things available elsewhere, though this particular set of changes may warrant a detailed section in the release notes. - bot.db.locale -> redbot.core.i18n.get_locale - Note: This one already existed. - bot.db.help -> redbot.core.commands.help.HelpSettings - bot db whitelist/blaclist? -> bot.allowed_by_whitelist_blacklist - This has also been made a single cannonical function for this purpose including check usage - bot color? -> bot.get_embed_color/bot.get_embed_colour - bot.id.api_tokens? -> - bot.get_shared_api_tokens - bot.set_shared_api_tokens - bot.remove_shared_api_tokens -bot.db.prefix -> bot.get_valid_prefixes - (Note: This is a wrapper around bot.get_prefix) Other changes include - removing `bot.counter` as it was never used anywhere - Adding properties with helpful error messages for moved and renamed things - making bot.uptime a property with an error on set - adding a migration to the bot config for shared_api_tokens * Remove overly encompassing message redaction, eval is a risk, dont run in dev if you cant manage it * address Flame's feedback * rephrase example * changelog extras * You saw nothing
This commit is contained in:
parent
62dcebff94
commit
25614620db
1
changelog.d/2976.breaking.rst
Normal file
1
changelog.d/2976.breaking.rst
Normal file
@ -0,0 +1 @@
|
||||
Removes bot._counter, Makes a few more attrs private (cog_mgr, main_dir)
|
||||
@ -65,7 +65,7 @@ class Downloader(commands.Cog):
|
||||
The default cog install path.
|
||||
|
||||
"""
|
||||
return await self.bot.cog_mgr.install_path()
|
||||
return await self.bot._cog_mgr.install_path()
|
||||
|
||||
async def installed_cogs(self) -> Tuple[Installable]:
|
||||
"""Get info on installed cogs.
|
||||
|
||||
6
redbot/core/2976.feature.rst
Normal file
6
redbot/core/2976.feature.rst
Normal file
@ -0,0 +1,6 @@
|
||||
adds a few methods and classes replacing direct config access (which is no longer supported)
|
||||
|
||||
- ``redbot.core.Red.allowed_by_whitelist_blacklist``
|
||||
- ``redbot.core.Red.get_valid_prefixes``
|
||||
- ``redbot.core.Red.clear_shared_api_tokens``
|
||||
- ``redbot.core.commands.help.HelpSettings``
|
||||
@ -2,11 +2,12 @@ import asyncio
|
||||
import inspect
|
||||
import logging
|
||||
import os
|
||||
from collections import Counter
|
||||
from collections import namedtuple
|
||||
from datetime import datetime
|
||||
from enum import Enum
|
||||
from importlib.machinery import ModuleSpec
|
||||
from pathlib import Path
|
||||
from typing import Optional, Union, List, Dict
|
||||
from typing import Optional, Union, List, Dict, NoReturn
|
||||
|
||||
import discord
|
||||
from discord.ext.commands import when_mentioned_or
|
||||
@ -18,9 +19,14 @@ from .rpc import RPCMixin
|
||||
from .utils import common_filters
|
||||
|
||||
CUSTOM_GROUPS = "CUSTOM_GROUPS"
|
||||
SHARED_API_TOKENS = "SHARED_API_TOKENS"
|
||||
|
||||
log = logging.getLogger("redbot")
|
||||
|
||||
__all__ = ["RedBase", "Red", "ExitCodes"]
|
||||
|
||||
NotMessage = namedtuple("NotMessage", "guild")
|
||||
|
||||
|
||||
def _is_submodule(parent, child):
|
||||
return parent == child or child.startswith(parent + ".")
|
||||
@ -63,7 +69,6 @@ class RedBase(commands.GroupMixin, commands.bot.BotBase, RPCMixin): # pylint: d
|
||||
invite_perm=0,
|
||||
disabled_commands=[],
|
||||
disabled_command_msg="That command is disabled.",
|
||||
api_tokens={},
|
||||
extra_owner_destinations=[],
|
||||
owner_opt_out_list=[],
|
||||
schema_version=0,
|
||||
@ -87,6 +92,9 @@ class RedBase(commands.GroupMixin, commands.bot.BotBase, RPCMixin): # pylint: d
|
||||
self._config.init_custom(CUSTOM_GROUPS, 2)
|
||||
self._config.register_custom(CUSTOM_GROUPS)
|
||||
|
||||
self._config.init_custom(SHARED_API_TOKENS, 2)
|
||||
self._config.register_custom(SHARED_API_TOKENS)
|
||||
|
||||
async def prefix_manager(bot, message):
|
||||
if not cli_flags.prefix:
|
||||
global_prefix = await bot._config.prefix()
|
||||
@ -117,14 +125,12 @@ class RedBase(commands.GroupMixin, commands.bot.BotBase, RPCMixin): # pylint: d
|
||||
if "command_not_found" not in kwargs:
|
||||
kwargs["command_not_found"] = "Command {} not found.\n{}"
|
||||
|
||||
self._counter = Counter()
|
||||
self._uptime = None
|
||||
self._checked_time_accuracy = None
|
||||
self._color = discord.Embed.Empty # This is needed or color ends up 0x000000
|
||||
|
||||
self.main_dir = bot_dir
|
||||
|
||||
self.cog_mgr = CogManager()
|
||||
self._main_dir = bot_dir
|
||||
self._cog_mgr = CogManager()
|
||||
|
||||
super().__init__(*args, help_command=None, **kwargs)
|
||||
# Do not manually use the help formatter attribute here, see `send_help_for`,
|
||||
@ -134,9 +140,165 @@ class RedBase(commands.GroupMixin, commands.bot.BotBase, RPCMixin): # pylint: d
|
||||
|
||||
self._permissions_hooks: List[commands.CheckPredicate] = []
|
||||
|
||||
@property
|
||||
def cog_mgr(self) -> NoReturn:
|
||||
raise AttributeError("Please don't mess with the cog manager internals.")
|
||||
|
||||
@property
|
||||
def uptime(self) -> datetime:
|
||||
""" Allow access to the value, but we don't want cog creators setting it """
|
||||
return self._uptime
|
||||
|
||||
@uptime.setter
|
||||
def uptime(self, value) -> NoReturn:
|
||||
raise RuntimeError(
|
||||
"Hey, we're cool with sharing info about the uptime, but don't try and assign to it please."
|
||||
)
|
||||
|
||||
@property
|
||||
def db(self) -> NoReturn:
|
||||
raise AttributeError(
|
||||
"We really don't want you touching the bot config directly. "
|
||||
"If you need something in here, take a look at the exposed methods "
|
||||
"and use the one which corresponds to your needs or "
|
||||
"open an issue if you need an additional method for your use case."
|
||||
)
|
||||
|
||||
@property
|
||||
def counter(self) -> NoReturn:
|
||||
raise AttributeError(
|
||||
"Please make your own counter object by importing ``Counter`` from ``collections``."
|
||||
)
|
||||
|
||||
@property
|
||||
def color(self) -> NoReturn:
|
||||
raise AttributeError("Please fetch the embed color with `get_embed_color`")
|
||||
|
||||
@property
|
||||
def colour(self) -> NoReturn:
|
||||
raise AttributeError("Please fetch the embed colour with `get_embed_colour`")
|
||||
|
||||
async def allowed_by_whitelist_blacklist(
|
||||
self,
|
||||
who: Optional[Union[discord.Member, discord.User]] = None,
|
||||
*,
|
||||
who_id: Optional[int] = None,
|
||||
guild_id: Optional[int] = None,
|
||||
role_ids: Optional[List[int]] = None,
|
||||
) -> bool:
|
||||
"""
|
||||
This checks if a user or member is allowed to run things,
|
||||
as considered by Red's whitelist and blacklist.
|
||||
|
||||
If given a user object, this function will check the global lists
|
||||
|
||||
If given a member, this will additionally check guild lists
|
||||
|
||||
If omiting a user or member, you must provide a value for ``who_id``
|
||||
|
||||
You may also provide a value for ``guild_id`` in this case
|
||||
|
||||
If providing a member by guild and member ids,
|
||||
you should supply ``role_ids`` as well
|
||||
|
||||
Parameters
|
||||
----------
|
||||
who : Optional[Union[discord.Member, discord.User]]
|
||||
The user or member object to check
|
||||
|
||||
Other Parameters
|
||||
----------------
|
||||
who_id : Optional[int]
|
||||
The id of the user or member to check
|
||||
If not providing a value for ``who``, this is a required parameter.
|
||||
guild_id : Optional[int]
|
||||
When used in conjunction with a provided value for ``who_id``, checks
|
||||
the lists for the corresponding guild as well.
|
||||
role_ids : Optional[List[int]]
|
||||
When used with both ``who_id`` and ``guild_id``, checks the role ids provided.
|
||||
This is required for accurate checking of members in a guild if providing ids.
|
||||
|
||||
Raises
|
||||
------
|
||||
TypeError
|
||||
Did not provide ``who`` or ``who_id``
|
||||
"""
|
||||
# Contributor Note:
|
||||
# All config calls are delayed until needed in this section
|
||||
# All changes should be made keeping in mind that this is also used as a global check
|
||||
|
||||
guild = None
|
||||
mocked = False # used for an accurate delayed role id expansion later.
|
||||
if not who:
|
||||
if not who_id:
|
||||
raise TypeError("Must provide a value for either `who` or `who_id`")
|
||||
mocked = True
|
||||
who = discord.Object(id=who_id)
|
||||
if guild_id:
|
||||
guild = discord.Object(id=guild_id)
|
||||
else:
|
||||
guild = getattr(who, "guild", None)
|
||||
|
||||
if await self.is_owner(who):
|
||||
return True
|
||||
|
||||
global_whitelist = await self._config.whitelist()
|
||||
if global_whitelist:
|
||||
if who.id not in global_whitelist:
|
||||
return False
|
||||
else:
|
||||
# blacklist is only used when whitelist doesn't exist.
|
||||
global_blacklist = await self._config.blacklist()
|
||||
if who.id in global_blacklist:
|
||||
return False
|
||||
|
||||
if guild:
|
||||
# The delayed expansion of ids to check saves time in the DM case.
|
||||
# Converting to a set reduces the total lookup time in section
|
||||
if mocked:
|
||||
ids = {i for i in (who.id, *(role_ids or [])) if i != guild.id}
|
||||
else:
|
||||
# DEP-WARN
|
||||
# This uses member._roles (getattr is for the user case)
|
||||
# If this is removed upstream (undocumented)
|
||||
# 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}
|
||||
|
||||
guild_whitelist = await self._config.guild(guild).whitelist()
|
||||
if guild_whitelist:
|
||||
if ids.isdisjoint(guild_whitelist):
|
||||
return False
|
||||
else:
|
||||
guild_blacklist = self._config.guild(guild).blacklist()
|
||||
if not ids.isdisjoint(guild_blacklist):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
async def get_valid_prefixes(self, guild: Optional[discord.Guild] = None) -> List[str]:
|
||||
"""
|
||||
This gets the valid prefixes for a guild.
|
||||
|
||||
If not provided a guild (or passed None) it will give the DM prefixes.
|
||||
|
||||
This is just a fancy wrapper around ``get_prefix``
|
||||
|
||||
Parameters
|
||||
----------
|
||||
guild : Optional[discord.Guild]
|
||||
The guild you want prefixes for. Omit (or pass None) for the DM prefixes
|
||||
|
||||
Returns
|
||||
-------
|
||||
List[str]
|
||||
If a guild was specified, the valid prefixes in that guild.
|
||||
If a guild was not specified, the valid prefixes for DMs
|
||||
"""
|
||||
return await self.get_prefix(NotMessage(guild))
|
||||
|
||||
async def get_embed_color(self, location: discord.abc.Messageable) -> discord.Color:
|
||||
"""
|
||||
Get the embed color for a location.
|
||||
Get the embed color for a location. This takes into account all related settings.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
@ -170,6 +332,24 @@ class RedBase(commands.GroupMixin, commands.bot.BotBase, RPCMixin): # pylint: d
|
||||
await self._schema_0_to_1()
|
||||
schema_version += 1
|
||||
await self._config.schema_version.set(schema_version)
|
||||
if schema_version == 1:
|
||||
await self._schema_1_to_2()
|
||||
schema_version += 1
|
||||
await self._config.schema_version.set(schema_version)
|
||||
|
||||
async def _schema_1_to_2(self):
|
||||
"""
|
||||
This contains the migration of shared API tokens to a custom config scope
|
||||
"""
|
||||
|
||||
log.info("Moving shared API tokens to a custom group")
|
||||
all_shared_api_tokens = await self._config.get_raw("api_tokens", default={})
|
||||
for service_name, token_mapping in all_shared_api_tokens.items():
|
||||
service_partial = self._config.custom(SHARED_API_TOKENS, service_name)
|
||||
async with service_partial.all() as basically_bulk_update:
|
||||
basically_bulk_update.update(token_mapping)
|
||||
|
||||
await self._config.clear_raw("api_tokens")
|
||||
|
||||
async def _schema_0_to_1(self):
|
||||
"""
|
||||
@ -320,7 +500,7 @@ class RedBase(commands.GroupMixin, commands.bot.BotBase, RPCMixin): # pylint: d
|
||||
A Mapping of token names to tokens.
|
||||
This mapping exists because some services have multiple tokens.
|
||||
"""
|
||||
return await self._config.api_tokens.get_raw(service_name, default={})
|
||||
return await self._config.custom(SHARED_API_TOKENS, service_name).all()
|
||||
|
||||
async def set_shared_api_tokens(self, service_name: str, **tokens: str):
|
||||
"""
|
||||
@ -330,10 +510,44 @@ class RedBase(commands.GroupMixin, commands.bot.BotBase, RPCMixin): # pylint: d
|
||||
``set api`` command
|
||||
|
||||
This will not clear existing values not specified.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
service_name: str
|
||||
The service to set tokens for
|
||||
**tokens
|
||||
token_name -> token
|
||||
|
||||
Examples
|
||||
--------
|
||||
Setting the api_key for youtube from a value in a variable ``my_key``
|
||||
|
||||
>>> await ctx.bot.set_shared_api_tokens("youtube", api_key=my_key)
|
||||
"""
|
||||
|
||||
async with self._config.api_tokens.get_attr(service_name)() as method_abuse:
|
||||
method_abuse.update(**tokens)
|
||||
async with self._config.custom(SHARED_API_TOKENS, service_name).all() as group:
|
||||
group.update(tokens)
|
||||
|
||||
async def remove_shared_api_tokens(self, service_name: str, *token_names: str):
|
||||
"""
|
||||
Removes shared API tokens
|
||||
|
||||
Parameters
|
||||
----------
|
||||
service_name: str
|
||||
The service to remove tokens for
|
||||
*token_names: str
|
||||
The name of each token to be removed
|
||||
|
||||
Examples
|
||||
--------
|
||||
Removing the api_key for youtube
|
||||
|
||||
>>> await ctx.bot.remove_shared_api_tokens("youtube", "api_key")
|
||||
"""
|
||||
async with self._config.custom(SHARED_API_TOKENS, service_name).all() as group:
|
||||
for name in token_names:
|
||||
group.pop(name, None)
|
||||
|
||||
async def get_context(self, message, *, cls=commands.Context):
|
||||
return await super().get_context(message, cls=cls)
|
||||
|
||||
@ -21,7 +21,7 @@ def interactive_config(red, token_set, prefix_set):
|
||||
print("That doesn't look like a valid token.")
|
||||
token = ""
|
||||
if token:
|
||||
loop.run_until_complete(red.db.token.set(token))
|
||||
loop.run_until_complete(red._config.token.set(token))
|
||||
|
||||
if not prefix_set:
|
||||
prefix = ""
|
||||
@ -39,7 +39,7 @@ def interactive_config(red, token_set, prefix_set):
|
||||
if not confirm("> "):
|
||||
prefix = ""
|
||||
if prefix:
|
||||
loop.run_until_complete(red.db.prefix.set([prefix]))
|
||||
loop.run_until_complete(red._config.prefix.set([prefix]))
|
||||
|
||||
return token
|
||||
|
||||
|
||||
@ -317,7 +317,7 @@ class CogManagerUI(commands.Cog):
|
||||
"""
|
||||
Lists current cog paths in order of priority.
|
||||
"""
|
||||
cog_mgr = ctx.bot.cog_mgr
|
||||
cog_mgr = ctx.bot._cog_mgr
|
||||
install_path = await cog_mgr.install_path()
|
||||
core_path = cog_mgr.CORE_PATH
|
||||
cog_paths = await cog_mgr.user_defined_paths()
|
||||
@ -344,7 +344,7 @@ class CogManagerUI(commands.Cog):
|
||||
return
|
||||
|
||||
try:
|
||||
await ctx.bot.cog_mgr.add_path(path)
|
||||
await ctx.bot._cog_mgr.add_path(path)
|
||||
except ValueError as e:
|
||||
await ctx.send(str(e))
|
||||
else:
|
||||
@ -362,14 +362,14 @@ class CogManagerUI(commands.Cog):
|
||||
await ctx.send(_("Path numbers must be positive."))
|
||||
return
|
||||
|
||||
cog_paths = await ctx.bot.cog_mgr.user_defined_paths()
|
||||
cog_paths = await ctx.bot._cog_mgr.user_defined_paths()
|
||||
try:
|
||||
to_remove = cog_paths.pop(path_number)
|
||||
except IndexError:
|
||||
await ctx.send(_("That is an invalid path number."))
|
||||
return
|
||||
|
||||
await ctx.bot.cog_mgr.remove_path(to_remove)
|
||||
await ctx.bot._cog_mgr.remove_path(to_remove)
|
||||
await ctx.send(_("Path successfully removed."))
|
||||
|
||||
@commands.command()
|
||||
@ -385,7 +385,7 @@ class CogManagerUI(commands.Cog):
|
||||
await ctx.send(_("Path numbers must be positive."))
|
||||
return
|
||||
|
||||
all_paths = await ctx.bot.cog_mgr.user_defined_paths()
|
||||
all_paths = await ctx.bot._cog_mgr.user_defined_paths()
|
||||
try:
|
||||
to_move = all_paths.pop(from_)
|
||||
except IndexError:
|
||||
@ -398,7 +398,7 @@ class CogManagerUI(commands.Cog):
|
||||
await ctx.send(_("Invalid 'to' index."))
|
||||
return
|
||||
|
||||
await ctx.bot.cog_mgr.set_paths(all_paths)
|
||||
await ctx.bot._cog_mgr.set_paths(all_paths)
|
||||
await ctx.send(_("Paths reordered."))
|
||||
|
||||
@commands.command()
|
||||
@ -413,14 +413,14 @@ class CogManagerUI(commands.Cog):
|
||||
"""
|
||||
if path:
|
||||
if not path.is_absolute():
|
||||
path = (ctx.bot.main_dir / path).resolve()
|
||||
path = (ctx.bot._main_dir / path).resolve()
|
||||
try:
|
||||
await ctx.bot.cog_mgr.set_install_path(path)
|
||||
await ctx.bot._cog_mgr.set_install_path(path)
|
||||
except ValueError:
|
||||
await ctx.send(_("That path does not exist."))
|
||||
return
|
||||
|
||||
install_path = await ctx.bot.cog_mgr.install_path()
|
||||
install_path = await ctx.bot._cog_mgr.install_path()
|
||||
await ctx.send(
|
||||
_("The bot will install new cogs to the `{}` directory.").format(install_path)
|
||||
)
|
||||
@ -433,7 +433,7 @@ class CogManagerUI(commands.Cog):
|
||||
"""
|
||||
loaded = set(ctx.bot.extensions.keys())
|
||||
|
||||
all_cogs = set(await ctx.bot.cog_mgr.available_modules())
|
||||
all_cogs = set(await ctx.bot._cog_mgr.available_modules())
|
||||
|
||||
unloaded = all_cogs - loaded
|
||||
|
||||
|
||||
@ -1,3 +1,8 @@
|
||||
# Warning: The implementation below touches several private attributes.
|
||||
# While this implementation will be updated, and public interfaces maintained, derived classes
|
||||
# should not assume these private attributes are version safe, and use the provided HelpSettings
|
||||
# class for these settings.
|
||||
|
||||
# This is a full replacement of discord.py's help command
|
||||
#
|
||||
# At a later date, there should be things added to support extra formatter
|
||||
@ -29,6 +34,7 @@
|
||||
|
||||
import asyncio
|
||||
from collections import namedtuple
|
||||
from dataclasses import dataclass
|
||||
from typing import Union, List, AsyncIterator, Iterable, cast
|
||||
|
||||
import discord
|
||||
@ -40,7 +46,7 @@ from ..i18n import Translator
|
||||
from ..utils import menus, fuzzy_command_search, format_fuzzy_results
|
||||
from ..utils.chat_formatting import box, pagify
|
||||
|
||||
__all__ = ["red_help", "RedHelpFormatter"]
|
||||
__all__ = ["red_help", "RedHelpFormatter", "HelpSettings"]
|
||||
|
||||
T_ = Translator("Help", __file__)
|
||||
|
||||
@ -53,6 +59,36 @@ EmbedField = namedtuple("EmbedField", "name value inline")
|
||||
EMPTY_STRING = "\N{ZERO WIDTH SPACE}"
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class HelpSettings:
|
||||
"""
|
||||
A representation of help settings.
|
||||
"""
|
||||
|
||||
page_char_limit: int = 1000
|
||||
max_pages_in_guild: int = 2
|
||||
use_menus: bool = False
|
||||
show_hidden: bool = False
|
||||
verify_checks: bool = True
|
||||
verify_exists: bool = False
|
||||
tagline: str = ""
|
||||
|
||||
# Contrib Note: This is intentional to not accept the bot object
|
||||
# There are plans to allow guild and user specific help settings
|
||||
# Adding a non-context based method now would involve a breaking change later.
|
||||
# At a later date, more methods should be exposed for non-context based creation.
|
||||
#
|
||||
# This is also why we aren't just caching the
|
||||
# current state of these settings on the bot object.
|
||||
@classmethod
|
||||
async def from_context(cls, context: Context):
|
||||
"""
|
||||
Get the HelpSettings for the current context
|
||||
"""
|
||||
settings = await context.bot._config.help.all()
|
||||
return cls(**settings)
|
||||
|
||||
|
||||
class NoCommand(Exception):
|
||||
pass
|
||||
|
||||
|
||||
@ -87,7 +87,7 @@ class CoreLogic:
|
||||
|
||||
for name in cog_names:
|
||||
try:
|
||||
spec = await bot.cog_mgr.find_cog(name)
|
||||
spec = await bot._cog_mgr.find_cog(name)
|
||||
if spec:
|
||||
cogspecs.append((spec, name))
|
||||
else:
|
||||
@ -1146,7 +1146,7 @@ class Core(commands.Cog, CoreLogic):
|
||||
"""
|
||||
if ctx.channel.permissions_for(ctx.me).manage_messages:
|
||||
await ctx.message.delete()
|
||||
await ctx.bot._config.api_tokens.set_raw(service, value=tokens)
|
||||
await ctx.bot.set_shared_api_tokens(service, **tokens)
|
||||
await ctx.send(_("`{service}` API tokens have been set.").format(service=service))
|
||||
|
||||
@commands.group()
|
||||
@ -2198,7 +2198,7 @@ class Core(commands.Cog, CoreLogic):
|
||||
async def rpc_load(self, request):
|
||||
cog_name = request.params[0]
|
||||
|
||||
spec = await self.bot.cog_mgr.find_cog(cog_name)
|
||||
spec = await self.bot._cog_mgr.find_cog(cog_name)
|
||||
if spec is None:
|
||||
raise LookupError("No such cog found.")
|
||||
|
||||
|
||||
@ -61,19 +61,10 @@ class Dev(commands.Cog):
|
||||
return pagify(msg, delims=["\n", " "], priority=True, shorten_by=10)
|
||||
|
||||
@staticmethod
|
||||
def sanitize_output(ctx: commands.Context, keys: dict, input_: str) -> str:
|
||||
def sanitize_output(ctx: commands.Context, input_: str) -> str:
|
||||
"""Hides the bot's token from a string."""
|
||||
token = ctx.bot.http.token
|
||||
r = "[EXPUNGED]"
|
||||
result = input_.replace(token, r)
|
||||
result = result.replace(token.lower(), r)
|
||||
result = result.replace(token.upper(), r)
|
||||
for provider, data in keys.items():
|
||||
for name, key in data.items():
|
||||
result = result.replace(key, r)
|
||||
result = result.replace(key.upper(), r)
|
||||
result = result.replace(key.lower(), r)
|
||||
return result
|
||||
return re.sub(re.escape(token), "[EXPUNGED]", input_, re.I)
|
||||
|
||||
@commands.command()
|
||||
@checks.is_owner()
|
||||
@ -125,9 +116,7 @@ class Dev(commands.Cog):
|
||||
result = await result
|
||||
|
||||
self._last_result = result
|
||||
|
||||
api_keys = await ctx.bot._config.api_tokens()
|
||||
result = self.sanitize_output(ctx, api_keys, str(result))
|
||||
result = self.sanitize_output(ctx, str(result))
|
||||
|
||||
await ctx.send_interactive(self.get_pages(result), box_lang="py")
|
||||
|
||||
@ -191,8 +180,7 @@ class Dev(commands.Cog):
|
||||
msg = "{}{}".format(printed, result)
|
||||
else:
|
||||
msg = printed
|
||||
api_keys = await ctx.bot._config.api_tokens()
|
||||
msg = self.sanitize_output(ctx, api_keys, msg)
|
||||
msg = self.sanitize_output(ctx, msg)
|
||||
|
||||
await ctx.send_interactive(self.get_pages(msg), box_lang="py")
|
||||
|
||||
@ -276,8 +264,7 @@ class Dev(commands.Cog):
|
||||
elif value:
|
||||
msg = "{}".format(value)
|
||||
|
||||
api_keys = await ctx.bot._config.api_tokens()
|
||||
msg = self.sanitize_output(ctx, api_keys, msg)
|
||||
msg = self.sanitize_output(ctx, msg)
|
||||
|
||||
try:
|
||||
await ctx.send_interactive(self.get_pages(msg), box_lang="py")
|
||||
|
||||
@ -67,7 +67,7 @@ def init_events(bot, cli_flags):
|
||||
print("Loading packages...")
|
||||
for package in packages:
|
||||
try:
|
||||
spec = await bot.cog_mgr.find_cog(package)
|
||||
spec = await bot._cog_mgr.find_cog(package)
|
||||
await bot.load_extension(spec)
|
||||
except Exception as e:
|
||||
log.exception("Failed to load package {}".format(package), exc_info=e)
|
||||
@ -243,7 +243,6 @@ def init_events(bot, cli_flags):
|
||||
|
||||
@bot.event
|
||||
async def on_message(message):
|
||||
bot._counter["messages_read"] += 1
|
||||
await bot.process_commands(message)
|
||||
discord_now = message.created_at
|
||||
if (
|
||||
@ -260,14 +259,6 @@ def init_events(bot, cli_flags):
|
||||
)
|
||||
bot._checked_time_accuracy = discord_now
|
||||
|
||||
@bot.event
|
||||
async def on_resumed():
|
||||
bot._counter["sessions_resumed"] += 1
|
||||
|
||||
@bot.event
|
||||
async def on_command(command):
|
||||
bot._counter["processed_commands"] += 1
|
||||
|
||||
@bot.event
|
||||
async def on_command_add(command: commands.Command):
|
||||
disabled_commands = await bot._config.disabled_commands()
|
||||
|
||||
@ -4,34 +4,8 @@ from . import commands
|
||||
|
||||
def init_global_checks(bot):
|
||||
@bot.check_once
|
||||
async def global_perms(ctx):
|
||||
"""Check the user is/isn't globally whitelisted/blacklisted."""
|
||||
if await bot.is_owner(ctx.author):
|
||||
return True
|
||||
|
||||
whitelist = await bot._config.whitelist()
|
||||
if whitelist:
|
||||
return ctx.author.id in whitelist
|
||||
|
||||
return ctx.author.id not in await bot._config.blacklist()
|
||||
|
||||
@bot.check_once
|
||||
async def local_perms(ctx: commands.Context):
|
||||
"""Check the user is/isn't locally whitelisted/blacklisted."""
|
||||
if await bot.is_owner(ctx.author):
|
||||
return True
|
||||
elif ctx.guild is None:
|
||||
return True
|
||||
guild_settings = bot._config.guild(ctx.guild)
|
||||
local_blacklist = await guild_settings.blacklist()
|
||||
local_whitelist = await guild_settings.whitelist()
|
||||
|
||||
_ids = [r.id for r in ctx.author.roles if not r.is_default()]
|
||||
_ids.append(ctx.author.id)
|
||||
if local_whitelist:
|
||||
return any(i in local_whitelist for i in _ids)
|
||||
|
||||
return not any(i in local_blacklist for i in _ids)
|
||||
async def whiteblacklist_checks(ctx):
|
||||
return await ctx.bot.allowed_by_whitelist_blacklist(ctx.author)
|
||||
|
||||
@bot.check_once
|
||||
async def bots(ctx):
|
||||
|
||||
@ -5,9 +5,9 @@ __all__ = ["cog_mgr", "default_dir"]
|
||||
|
||||
@pytest.fixture()
|
||||
def cog_mgr(red):
|
||||
return red.cog_mgr
|
||||
return red._cog_mgr
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def default_dir(red):
|
||||
return red.main_dir
|
||||
return red._main_dir
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user