Skip to content

Commit 7b6dd00

Browse files
inklesspenarqunis
authored andcommitted
Check interaction type in command matching (#381)
This prevents errors from trying to invoke a message interaction on a user command or vice versa. Fixes #380
1 parent b703be2 commit 7b6dd00

File tree

3 files changed

+33
-6
lines changed

3 files changed

+33
-6
lines changed

src/dispatch/slash.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use crate::serenity_prelude as serenity;
55
/// Check if the interaction with the given name and arguments matches any framework command
66
fn find_matching_command<'a, 'b, U, E>(
77
interaction_name: &str,
8+
interaction_kind: serenity::CommandType,
89
interaction_options: &'b [serenity::ResolvedOption<'b>],
910
commands: &'a [crate::Command<U, E>],
1011
parent_commands: &mut Vec<&'a crate::Command<U, E>>,
@@ -16,6 +17,19 @@ fn find_matching_command<'a, 'b, U, E>(
1617
return None;
1718
}
1819

20+
// Discord allows commands with the same name as long as they have different types.
21+
match interaction_kind {
22+
serenity::CommandType::ChatInput => {
23+
cmd.slash_action?;
24+
}
25+
serenity::CommandType::User | serenity::CommandType::Message => {
26+
cmd.context_menu_action
27+
.map(serenity::CommandType::from)
28+
.filter(|kind| kind == &interaction_kind)?;
29+
}
30+
_ => unimplemented!(),
31+
}
32+
1933
if let Some((sub_name, sub_interaction)) =
2034
interaction_options
2135
.iter()
@@ -26,7 +40,13 @@ fn find_matching_command<'a, 'b, U, E>(
2640
})
2741
{
2842
parent_commands.push(cmd);
29-
find_matching_command(sub_name, sub_interaction, &cmd.subcommands, parent_commands)
43+
find_matching_command(
44+
sub_name,
45+
interaction_kind,
46+
sub_interaction,
47+
&cmd.subcommands,
48+
parent_commands,
49+
)
3050
} else {
3151
Some((cmd, interaction_options))
3252
}
@@ -50,6 +70,7 @@ fn extract_command<'a, U, E>(
5070
) -> Result<crate::ApplicationContext<'a, U, E>, crate::FrameworkError<'a, U, E>> {
5171
let search_result = find_matching_command(
5272
&interaction.data.name,
73+
interaction.data.kind,
5374
options,
5475
&framework.options.commands,
5576
parent_commands,

src/structs/command.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -250,11 +250,7 @@ impl<U, E> Command<U, E> {
250250

251251
// TODO: localization?
252252
let name = self.context_menu_name.as_deref().unwrap_or(&self.name);
253-
let mut builder = serenity::CreateCommand::new(name).kind(match context_menu_action {
254-
crate::ContextMenuCommandAction::User(_) => serenity::CommandType::User,
255-
crate::ContextMenuCommandAction::Message(_) => serenity::CommandType::Message,
256-
crate::ContextMenuCommandAction::__NonExhaustive => unreachable!(),
257-
});
253+
let mut builder = serenity::CreateCommand::new(name).kind(context_menu_action.into());
258254

259255
// This is_empty check is needed because Discord special cases empty
260256
// default_member_permissions to mean "admin-only"

src/structs/slash.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,16 @@ impl<U, E> Clone for ContextMenuCommandAction<U, E> {
109109
}
110110
}
111111

112+
impl<U, E> From<ContextMenuCommandAction<U, E>> for serenity::CommandType {
113+
fn from(value: ContextMenuCommandAction<U, E>) -> Self {
114+
match value {
115+
ContextMenuCommandAction::User(_) => serenity::CommandType::User,
116+
ContextMenuCommandAction::Message(_) => serenity::CommandType::Message,
117+
ContextMenuCommandAction::__NonExhaustive => unreachable!(),
118+
}
119+
}
120+
}
121+
112122
/// A single drop-down choice in a slash command choice parameter
113123
#[derive(Debug, Clone)]
114124
pub struct CommandParameterChoice {

0 commit comments

Comments
 (0)