mirror of
https://github.com/Cog-Creators/Red-DiscordBot.git
synced 2025-11-06 11:18:54 -05:00
update for d.py 1.3 (#3445)
* update for d.py 1.3 * Update redbot/core/commands/commands.py Co-Authored-By: Danny <Rapptz@users.noreply.github.com> * a few more places we use owner info * add the cli flag + handling * set fix * Handle MaxConcurrencyReached. * Bump `aiohttp-json-rpc` Co-authored-by: Danny <Rapptz@users.noreply.github.com> Co-authored-by: Kowlin <Kowlin@users.noreply.github.com> Co-authored-by: jack1142 <6032823+jack1142@users.noreply.github.com>
This commit is contained in:
parent
498d0d22fb
commit
2ac4dde729
@ -27,6 +27,7 @@ from types import MappingProxyType
|
|||||||
|
|
||||||
import discord
|
import discord
|
||||||
from discord.ext.commands import when_mentioned_or
|
from discord.ext.commands import when_mentioned_or
|
||||||
|
from discord.ext.commands.bot import BotBase
|
||||||
|
|
||||||
from . import Config, i18n, commands, errors, drivers, modlog, bank
|
from . import Config, i18n, commands, errors, drivers, modlog, bank
|
||||||
from .cog_manager import CogManager, CogManagerUI
|
from .cog_manager import CogManager, CogManagerUI
|
||||||
@ -59,7 +60,7 @@ def _is_submodule(parent, child):
|
|||||||
|
|
||||||
|
|
||||||
# barely spurious warning caused by our intentional shadowing
|
# barely spurious warning caused by our intentional shadowing
|
||||||
class RedBase(commands.GroupMixin, commands.bot.BotBase, RPCMixin): # pylint: disable=no-member
|
class RedBase(commands.GroupMixin, BotBase, RPCMixin): # pylint: disable=no-member
|
||||||
"""Mixin for the main bot class.
|
"""Mixin for the main bot class.
|
||||||
|
|
||||||
This exists because `Red` inherits from `discord.AutoShardedClient`, which
|
This exists because `Red` inherits from `discord.AutoShardedClient`, which
|
||||||
@ -150,6 +151,7 @@ class RedBase(commands.GroupMixin, commands.bot.BotBase, RPCMixin): # pylint: d
|
|||||||
|
|
||||||
self._main_dir = bot_dir
|
self._main_dir = bot_dir
|
||||||
self._cog_mgr = CogManager()
|
self._cog_mgr = CogManager()
|
||||||
|
self._use_team_features = cli_flags.use_team_features
|
||||||
super().__init__(*args, help_command=None, **kwargs)
|
super().__init__(*args, help_command=None, **kwargs)
|
||||||
# Do not manually use the help formatter attribute here, see `send_help_for`,
|
# Do not manually use the help formatter attribute here, see `send_help_for`,
|
||||||
# for a documented API. The internals of this object are still subject to change.
|
# for a documented API. The internals of this object are still subject to change.
|
||||||
@ -627,10 +629,42 @@ class RedBase(commands.GroupMixin, commands.bot.BotBase, RPCMixin): # pylint: d
|
|||||||
global_setting = await self._config.embeds()
|
global_setting = await self._config.embeds()
|
||||||
return global_setting
|
return global_setting
|
||||||
|
|
||||||
async def is_owner(self, user) -> bool:
|
async def is_owner(self, user: Union[discord.User, discord.Member]) -> bool:
|
||||||
|
"""
|
||||||
|
Determines if the user should be considered a bot owner.
|
||||||
|
|
||||||
|
This takes into account CLI flags and application ownership.
|
||||||
|
|
||||||
|
By default,
|
||||||
|
application team members are not considered owners,
|
||||||
|
while individual application owners are.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
user: Union[discord.User, discord.Member]
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
bool
|
||||||
|
"""
|
||||||
if user.id in self._co_owners:
|
if user.id in self._co_owners:
|
||||||
return True
|
return True
|
||||||
return await super().is_owner(user)
|
|
||||||
|
if self.owner_id:
|
||||||
|
return self.owner_id == user.id
|
||||||
|
elif self.owner_ids:
|
||||||
|
return user.id in self.owner_ids
|
||||||
|
else:
|
||||||
|
app = await self.application_info()
|
||||||
|
if app.team:
|
||||||
|
if self._use_team_features:
|
||||||
|
self.owner_ids = ids = {m.id for m in app.team.members}
|
||||||
|
return user.id in ids
|
||||||
|
else:
|
||||||
|
self.owner_id = owner_id = app.owner.id
|
||||||
|
return user.id == owner_id
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
async def is_admin(self, member: discord.Member) -> bool:
|
async def is_admin(self, member: discord.Member) -> bool:
|
||||||
"""Checks if a member is an admin of their guild."""
|
"""Checks if a member is an admin of their guild."""
|
||||||
@ -1069,10 +1103,11 @@ class RedBase(commands.GroupMixin, commands.bot.BotBase, RPCMixin): # pylint: d
|
|||||||
await self.wait_until_red_ready()
|
await self.wait_until_red_ready()
|
||||||
destinations = []
|
destinations = []
|
||||||
opt_outs = await self._config.owner_opt_out_list()
|
opt_outs = await self._config.owner_opt_out_list()
|
||||||
for user_id in (self.owner_id, *self._co_owners):
|
team_ids = () if not self._use_team_features else self.owner_ids
|
||||||
|
for user_id in set((self.owner_id, *self._co_owners, *team_ids)):
|
||||||
if user_id not in opt_outs:
|
if user_id not in opt_outs:
|
||||||
user = self.get_user(user_id)
|
user = self.get_user(user_id)
|
||||||
if user:
|
if user and not user.bot: # user.bot is possible with flags and teams
|
||||||
destinations.append(user)
|
destinations.append(user)
|
||||||
else:
|
else:
|
||||||
log.warning(
|
log.warning(
|
||||||
|
|||||||
@ -200,6 +200,18 @@ def parse_cli_flags(args):
|
|||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"instance_name", nargs="?", help="Name of the bot instance created during `redbot-setup`."
|
"instance_name", nargs="?", help="Name of the bot instance created during `redbot-setup`."
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--team-members-are-owners",
|
||||||
|
action="store_true",
|
||||||
|
dest="use_team_features",
|
||||||
|
default=False,
|
||||||
|
help=(
|
||||||
|
"Treat application team members as owners. "
|
||||||
|
"This is off by default. Owners can load and run arbitrary code. "
|
||||||
|
"Do not enable if you would not trust all of your team members with "
|
||||||
|
"all of the data on the host machine."
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
args = parser.parse_args(args)
|
args = parser.parse_args(args)
|
||||||
|
|
||||||
|
|||||||
@ -330,15 +330,27 @@ class Command(CogCommandMixin, commands.Command):
|
|||||||
if not change_permission_state:
|
if not change_permission_state:
|
||||||
ctx.permission_state = original_state
|
ctx.permission_state = original_state
|
||||||
|
|
||||||
async def _verify_checks(self, ctx):
|
async def prepare(self, ctx):
|
||||||
|
ctx.command = self
|
||||||
|
|
||||||
if not self.enabled:
|
if not self.enabled:
|
||||||
raise commands.DisabledCommand(f"{self.name} command is disabled")
|
raise commands.DisabledCommand(f"{self.name} command is disabled")
|
||||||
|
|
||||||
if not (await self.can_run(ctx, change_permission_state=True)):
|
if not await self.can_run(ctx, change_permission_state=True):
|
||||||
raise commands.CheckFailure(
|
raise commands.CheckFailure(
|
||||||
f"The check functions for command {self.qualified_name} failed."
|
f"The check functions for command {self.qualified_name} failed."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if self.cooldown_after_parsing:
|
||||||
|
await self._parse_arguments(ctx)
|
||||||
|
self._prepare_cooldowns(ctx)
|
||||||
|
else:
|
||||||
|
self._prepare_cooldowns(ctx)
|
||||||
|
await self._parse_arguments(ctx)
|
||||||
|
if self._max_concurrency is not None:
|
||||||
|
await self._max_concurrency.acquire(ctx)
|
||||||
|
await self.call_before_hooks(ctx)
|
||||||
|
|
||||||
async def do_conversion(
|
async def do_conversion(
|
||||||
self, ctx: "Context", converter, argument: str, param: inspect.Parameter
|
self, ctx: "Context", converter, argument: str, param: inspect.Parameter
|
||||||
):
|
):
|
||||||
@ -625,14 +637,14 @@ class Group(GroupMixin, Command, CogGroupMixin, commands.Group):
|
|||||||
|
|
||||||
if ctx.invoked_subcommand is None or self == ctx.invoked_subcommand:
|
if ctx.invoked_subcommand is None or self == ctx.invoked_subcommand:
|
||||||
if self.autohelp and not self.invoke_without_command:
|
if self.autohelp and not self.invoke_without_command:
|
||||||
await self._verify_checks(ctx)
|
await self.can_run(ctx, change_permission_state=True)
|
||||||
await ctx.send_help()
|
await ctx.send_help()
|
||||||
elif self.invoke_without_command:
|
elif self.invoke_without_command:
|
||||||
# So invoke_without_command when a subcommand of this group is invoked
|
# So invoke_without_command when a subcommand of this group is invoked
|
||||||
# will skip the the invokation of *this* command. However, because of
|
# will skip the the invokation of *this* command. However, because of
|
||||||
# how our permissions system works, we don't want it to skip the checks
|
# how our permissions system works, we don't want it to skip the checks
|
||||||
# as well.
|
# as well.
|
||||||
await self._verify_checks(ctx)
|
await self.can_run(ctx, change_permission_state=True)
|
||||||
# this is actually why we don't prepare earlier.
|
# this is actually why we don't prepare earlier.
|
||||||
|
|
||||||
await super().invoke(ctx)
|
await super().invoke(ctx)
|
||||||
@ -778,6 +790,3 @@ class _AlwaysAvailableCommand(Command):
|
|||||||
|
|
||||||
async def can_run(self, ctx, *args, **kwargs) -> bool:
|
async def can_run(self, ctx, *args, **kwargs) -> bool:
|
||||||
return not ctx.author.bot
|
return not ctx.author.bot
|
||||||
|
|
||||||
async def _verify_checks(self, ctx) -> bool:
|
|
||||||
return not ctx.author.bot
|
|
||||||
|
|||||||
@ -757,16 +757,10 @@ class _RulesDict(Dict[Union[int, str], PermState]):
|
|||||||
|
|
||||||
|
|
||||||
def _validate_perms_dict(perms: Dict[str, bool]) -> None:
|
def _validate_perms_dict(perms: Dict[str, bool]) -> None:
|
||||||
|
invalid_keys = set(perms.keys()) - set(discord.Permissions.VALID_FLAGS)
|
||||||
|
if invalid_keys:
|
||||||
|
raise TypeError(f"Invalid perm name(s): {', '.join(invalid_keys)}")
|
||||||
for perm, value in perms.items():
|
for perm, value in perms.items():
|
||||||
try:
|
|
||||||
attr = getattr(discord.Permissions, perm)
|
|
||||||
except AttributeError:
|
|
||||||
attr = None
|
|
||||||
|
|
||||||
if attr is None or not isinstance(attr, property):
|
|
||||||
# We reject invalid permissions
|
|
||||||
raise TypeError(f"Unknown permission name '{perm}'")
|
|
||||||
|
|
||||||
if value is not True:
|
if value is not True:
|
||||||
# We reject any permission not specified as 'True', since this is the only value which
|
# We reject any permission not specified as 'True', since this is the only value which
|
||||||
# makes practical sense.
|
# makes practical sense.
|
||||||
|
|||||||
@ -319,7 +319,10 @@ class Core(commands.Cog, CoreLogic):
|
|||||||
python_version = "[{}.{}.{}]({})".format(*sys.version_info[:3], python_url)
|
python_version = "[{}.{}.{}]({})".format(*sys.version_info[:3], python_url)
|
||||||
red_version = "[{}]({})".format(__version__, red_pypi)
|
red_version = "[{}]({})".format(__version__, red_pypi)
|
||||||
app_info = await self.bot.application_info()
|
app_info = await self.bot.application_info()
|
||||||
owner = app_info.owner
|
if app_info.team:
|
||||||
|
owner = app_info.team.name
|
||||||
|
else:
|
||||||
|
owner = app_info.owner
|
||||||
custom_info = await self.bot._config.custom_info()
|
custom_info = await self.bot._config.custom_info()
|
||||||
|
|
||||||
async with aiohttp.ClientSession() as session:
|
async with aiohttp.ClientSession() as session:
|
||||||
|
|||||||
@ -49,8 +49,13 @@ def init_events(bot, cli_flags):
|
|||||||
users = len(set([m for m in bot.get_all_members()]))
|
users = len(set([m for m in bot.get_all_members()]))
|
||||||
|
|
||||||
app_info = await bot.application_info()
|
app_info = await bot.application_info()
|
||||||
if bot.owner_id is None:
|
|
||||||
bot.owner_id = app_info.owner.id
|
if app_info.team:
|
||||||
|
if bot._use_team_features:
|
||||||
|
bot.owner_ids = {m.id for m in app_info.team.members}
|
||||||
|
else:
|
||||||
|
if bot.owner_id is None:
|
||||||
|
bot.owner_id = app_info.owner.id
|
||||||
|
|
||||||
try:
|
try:
|
||||||
invite_url = discord.utils.oauth_url(app_info.id)
|
invite_url = discord.utils.oauth_url(app_info.id)
|
||||||
@ -213,6 +218,12 @@ def init_events(bot, cli_flags):
|
|||||||
),
|
),
|
||||||
delete_after=error.retry_after,
|
delete_after=error.retry_after,
|
||||||
)
|
)
|
||||||
|
elif isinstance(error, commands.MaxConcurrencyReached):
|
||||||
|
await ctx.send(
|
||||||
|
"Too many people using this command. It can only be used {} time(s) per {} concurrently.".format(
|
||||||
|
error.number, error.per.name
|
||||||
|
)
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
log.exception(type(error).__name__, exc_info=error)
|
log.exception(type(error).__name__, exc_info=error)
|
||||||
|
|
||||||
|
|||||||
@ -27,7 +27,7 @@ packages = find_namespace:
|
|||||||
python_requires = >=3.8.1
|
python_requires = >=3.8.1
|
||||||
install_requires =
|
install_requires =
|
||||||
aiohttp==3.6.2
|
aiohttp==3.6.2
|
||||||
aiohttp-json-rpc==0.12.1
|
aiohttp-json-rpc==0.12.2
|
||||||
aiosqlite==0.11.0
|
aiosqlite==0.11.0
|
||||||
appdirs==1.4.3
|
appdirs==1.4.3
|
||||||
apsw-wheels==3.30.1.post3
|
apsw-wheels==3.30.1.post3
|
||||||
@ -38,7 +38,7 @@ install_requires =
|
|||||||
Click==7.0
|
Click==7.0
|
||||||
colorama==0.4.3
|
colorama==0.4.3
|
||||||
contextlib2==0.5.5
|
contextlib2==0.5.5
|
||||||
discord.py==1.2.5
|
discord.py==1.3.0
|
||||||
distro==1.4.0; sys_platform == "linux"
|
distro==1.4.0; sys_platform == "linux"
|
||||||
fuzzywuzzy==0.17.0
|
fuzzywuzzy==0.17.0
|
||||||
idna==2.8
|
idna==2.8
|
||||||
@ -46,7 +46,7 @@ install_requires =
|
|||||||
python-Levenshtein-wheels==0.13.1
|
python-Levenshtein-wheels==0.13.1
|
||||||
pytz==2019.3
|
pytz==2019.3
|
||||||
PyYAML==5.3
|
PyYAML==5.3
|
||||||
Red-Lavalink==0.4.1
|
Red-Lavalink==0.4.2
|
||||||
schema==0.7.1
|
schema==0.7.1
|
||||||
tqdm==4.41.1
|
tqdm==4.41.1
|
||||||
uvloop==0.14.0; sys_platform != "win32" and platform_python_implementation == "CPython"
|
uvloop==0.14.0; sys_platform != "win32" and platform_python_implementation == "CPython"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user