Allow force enabling app commands using flag in extras (#6018)

This commit is contained in:
Flame442 2023-04-14 17:59:21 -04:00 committed by GitHub
parent ccdd1ca892
commit aa51fd9ad1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 98 additions and 25 deletions

View File

@ -4168,7 +4168,14 @@ slash list
**Description** **Description**
List the slash commands the bot can see, and whether or not they are enabled. List the slash commands the bot can see, and whether or not they are enabled.
This command shows the state that will be changed to when ``[p]slash sync`` is run. This command shows the state that will be changed to when ``[p]slash sync`` is run.
Commands from the same cog are grouped, with the cog name as the header.
The prefix denotes the state of the command:
- Commands starting with ``- `` have not yet been enabled.
- Commands starting with ``+ `` have been manually enabled.
- Commands starting with ``++`` have been enabled by the cog author, and cannot be disabled.
.. _core-command-slash-sync: .. _core-command-slash-sync:

View File

@ -1930,6 +1930,8 @@ class Red(
self.dispatch("command_add", subcommand) self.dispatch("command_add", subcommand)
if permissions_not_loaded: if permissions_not_loaded:
subcommand.requires.ready_event.set() subcommand.requires.ready_event.set()
if isinstance(command, (commands.HybridCommand, commands.HybridGroup)):
command.app_command.extras = command.extras
def remove_command(self, name: str, /) -> Optional[commands.Command]: def remove_command(self, name: str, /) -> Optional[commands.Command]:
command = super().remove_command(name) command = super().remove_command(name)

View File

@ -2045,11 +2045,22 @@ class Core(commands.commands._RuleDropper, commands.Cog, CoreLogic):
await ctx.send(_("Command type must be one of `slash`, `message`, or `user`.")) await ctx.send(_("Command type must be one of `slash`, `message`, or `user`."))
return return
existing = self.bot.tree.get_command(command_name, type=raw_type)
if existing is not None and existing.extras.get("red_force_enable", False):
await ctx.send(
_(
"That application command has been set as required for the cog to function "
"by the author, and cannot be disabled. "
"The cog must be unloaded to remove the command."
)
)
return
current_settings = await self.bot.list_enabled_app_commands() current_settings = await self.bot.list_enabled_app_commands()
current_settings = current_settings[command_type] current_settings = current_settings[command_type]
if command_name not in current_settings: if command_name not in current_settings:
await ctx.send(_("That application command is already disabled.")) await ctx.send(_("That application command is already disabled or does not exist."))
return return
await self.bot.disable_app_command(command_name, raw_type) await self.bot.disable_app_command(command_name, raw_type)
@ -2198,6 +2209,12 @@ class Core(commands.commands._RuleDropper, commands.Cog, CoreLogic):
"""List the slash commands the bot can see, and whether or not they are enabled. """List the slash commands the bot can see, and whether or not they are enabled.
This command shows the state that will be changed to when `[p]slash sync` is run. This command shows the state that will be changed to when `[p]slash sync` is run.
Commands from the same cog are grouped, with the cog name as the header.
The prefix denotes the state of the command:
- Commands starting with `- ` have not yet been enabled.
- Commands starting with `+ ` have been manually enabled.
- Commands starting with `++` have been enabled by the cog author, and cannot be disabled.
""" """
cog_commands = defaultdict(list) cog_commands = defaultdict(list)
slash_command_names = set() slash_command_names = set()
@ -2208,13 +2225,27 @@ class Core(commands.commands._RuleDropper, commands.Cog, CoreLogic):
module = command.module module = command.module
if "." in module: if "." in module:
module = module[: module.find(".")] module = module[: module.find(".")]
cog_commands[module].append((command.name, discord.AppCommandType.chat_input, True)) cog_commands[module].append(
(
command.name,
discord.AppCommandType.chat_input,
True,
command.extras.get("red_force_enable", False),
)
)
slash_command_names.add(command.name) slash_command_names.add(command.name)
for command in self.bot.tree._disabled_global_commands.values(): for command in self.bot.tree._disabled_global_commands.values():
module = command.module module = command.module
if "." in module: if "." in module:
module = module[: module.find(".")] module = module[: module.find(".")]
cog_commands[module].append((command.name, discord.AppCommandType.chat_input, False)) cog_commands[module].append(
(
command.name,
discord.AppCommandType.chat_input,
False,
command.extras.get("red_force_enable", False),
)
)
for key, command in self.bot.tree._context_menus.items(): for key, command in self.bot.tree._context_menus.items():
# Filter out guild context menus # Filter out guild context menus
if key[1] is not None: if key[1] is not None:
@ -2222,7 +2253,9 @@ class Core(commands.commands._RuleDropper, commands.Cog, CoreLogic):
module = command.module module = command.module
if "." in module: if "." in module:
module = module[: module.find(".")] module = module[: module.find(".")]
cog_commands[module].append((command.name, command.type, True)) cog_commands[module].append(
(command.name, command.type, True, command.extras.get("red_force_enable", False))
)
if command.type is discord.AppCommandType.message: if command.type is discord.AppCommandType.message:
message_command_names.add(command.name) message_command_names.add(command.name)
elif command.type is discord.AppCommandType.user: elif command.type is discord.AppCommandType.user:
@ -2231,7 +2264,9 @@ class Core(commands.commands._RuleDropper, commands.Cog, CoreLogic):
module = command.module module = command.module
if "." in module: if "." in module:
module = module[: module.find(".")] module = module[: module.find(".")]
cog_commands[module].append((command.name, command.type, False)) cog_commands[module].append(
(command.name, command.type, False, command.extras.get("red_force_enable", False))
)
# Commands added with evals will come from __main__, make them unknown instead # Commands added with evals will come from __main__, make them unknown instead
if "__main__" in cog_commands: if "__main__" in cog_commands:
@ -2245,9 +2280,13 @@ class Core(commands.commands._RuleDropper, commands.Cog, CoreLogic):
unknown_message = set(enabled_commands["message"]) - message_command_names unknown_message = set(enabled_commands["message"]) - message_command_names
unknown_user = set(enabled_commands["user"]) - user_command_names unknown_user = set(enabled_commands["user"]) - user_command_names
unknown_slash = [(n, discord.AppCommandType.chat_input, True) for n in unknown_slash] unknown_slash = [
unknown_message = [(n, discord.AppCommandType.message, True) for n in unknown_message] (n, discord.AppCommandType.chat_input, True, False) for n in unknown_slash
unknown_user = [(n, discord.AppCommandType.user, True) for n in unknown_user] ]
unknown_message = [
(n, discord.AppCommandType.message, True, False) for n in unknown_message
]
unknown_user = [(n, discord.AppCommandType.user, True, False) for n in unknown_user]
cog_commands["(unknown)"].extend(unknown_slash) cog_commands["(unknown)"].extend(unknown_slash)
cog_commands["(unknown)"].extend(unknown_message) cog_commands["(unknown)"].extend(unknown_message)
@ -2263,8 +2302,14 @@ class Core(commands.commands._RuleDropper, commands.Cog, CoreLogic):
msg = "" msg = ""
for cog in sorted(cog_commands.keys()): for cog in sorted(cog_commands.keys()):
msg += cog + "\n" msg += cog + "\n"
for name, raw_command_type, enabled in sorted(cog_commands[cog], key=lambda v: v[0]): for name, raw_command_type, enabled, forced in sorted(
diff = "+ " if enabled else "- " cog_commands[cog], key=lambda v: v[0]
):
diff = "- "
if forced:
diff = "++ "
elif enabled:
diff = "+ "
command_type = "unknown" command_type = "unknown"
if raw_command_type is discord.AppCommandType.chat_input: if raw_command_type is discord.AppCommandType.chat_input:
command_type = "slash" command_type = "slash"

View File

@ -61,7 +61,11 @@ class RedTree(CommandTree):
Commands will be internally stored until enabled by ``[p]slash enable``. Commands will be internally stored until enabled by ``[p]slash enable``.
""" """
# Allow guild specific commands to bypass the internals for development # Allow guild specific commands to bypass the internals for development
if guild is not MISSING or guilds is not MISSING: if (
guild is not MISSING
or guilds is not MISSING
or command.extras.get("red_force_enable", False)
):
return super().add_command( return super().add_command(
command, *args, guild=guild, guilds=guilds, override=override, **kwargs command, *args, guild=guild, guilds=guilds, override=override, **kwargs
) )
@ -171,45 +175,60 @@ class RedTree(CommandTree):
""" """
enabled_commands = await self.client.list_enabled_app_commands() enabled_commands = await self.client.list_enabled_app_commands()
to_add_commands = [] to_add_commands = set()
to_add_context = [] to_add_context = set()
to_remove_commands = [] to_remove_commands = set()
to_remove_context = [] to_remove_context = set()
# Add commands # Add commands
for command in enabled_commands["slash"]: for command in enabled_commands["slash"]:
if command in self._disabled_global_commands: if command in self._disabled_global_commands:
to_add_commands.append(command) to_add_commands.add(command)
# Add context # Add context
for command in enabled_commands["message"]: for command in enabled_commands["message"]:
key = (command, None, discord.AppCommandType.message.value) key = (command, None, discord.AppCommandType.message.value)
if key in self._disabled_context_menus: if key in self._disabled_context_menus:
to_add_context.append(key) to_add_context.add(key)
for command in enabled_commands["user"]: for command in enabled_commands["user"]:
key = (command, None, discord.AppCommandType.user.value) key = (command, None, discord.AppCommandType.user.value)
if key in self._disabled_context_menus: if key in self._disabled_context_menus:
to_add_context.append(key) to_add_context.add(key)
# Add force enabled commands
for command, command_obj in self._disabled_global_commands.items():
if command_obj.extras.get("red_force_enable", False):
to_add_commands.add(command)
# Add force enabled context
for key, command_obj in self._disabled_context_menus.items():
if command_obj.extras.get("red_force_enable", False):
to_add_context.add(key)
# Remove commands # Remove commands
for command in self._global_commands: for command, command_obj in self._global_commands.items():
if command not in enabled_commands["slash"]: if command not in enabled_commands["slash"] and not command_obj.extras.get(
to_remove_commands.append((command, discord.AppCommandType.chat_input)) "red_force_enable", False
):
to_remove_commands.add((command, discord.AppCommandType.chat_input))
# Remove context # Remove context
for command, guild_id, command_type in self._context_menus: for key, command_obj in self._context_menus.items():
command, guild_id, command_type = key
if guild_id is not None: if guild_id is not None:
continue continue
if ( if (
discord.AppCommandType(command_type) is discord.AppCommandType.message discord.AppCommandType(command_type) is discord.AppCommandType.message
and command not in enabled_commands["message"] and command not in enabled_commands["message"]
and not command_obj.extras.get("red_force_enable", False)
): ):
to_remove_context.append((command, discord.AppCommandType.message)) to_remove_context.add((command, discord.AppCommandType.message))
elif ( elif (
discord.AppCommandType(command_type) is discord.AppCommandType.user discord.AppCommandType(command_type) is discord.AppCommandType.user
and command not in enabled_commands["user"] and command not in enabled_commands["user"]
and not command_obj.extras.get("red_force_enable", False)
): ):
to_remove_context.append((command, discord.AppCommandType.user)) to_remove_context.add((command, discord.AppCommandType.user))
# Actually add/remove # Actually add/remove
for command in to_add_commands: for command in to_add_commands: