diff --git a/src/dispatch/permissions/application.rs b/src/dispatch/permissions/application.rs index e892c29c8ee..eabe520edc7 100644 --- a/src/dispatch/permissions/application.rs +++ b/src/dispatch/permissions/application.rs @@ -1,8 +1,18 @@ //! Application command permissions calculation -use crate::serenity_prelude as serenity; +use crate::{serenity::Permissions, serenity_prelude as serenity}; use super::PermissionsInfo; +/// Checks if a ChannelType is equal to a known thread type. +fn is_thread(kind: serenity::ChannelType) -> bool { + matches!( + kind, + serenity::ChannelType::NewsThread + | serenity::ChannelType::PrivateThread + | serenity::ChannelType::PublicThread + ) +} + /// Gets the permissions of the ctx author and the bot. pub(super) fn get_author_and_bot_permissions( interaction: &serenity::CommandInteraction, @@ -11,10 +21,22 @@ pub(super) fn get_author_and_bot_permissions( let author_member = interaction.member.as_ref().expect(err); let err = "should always be some as inside interaction"; - let author_permissions = author_member.permissions.expect(err); + let mut author_permissions = author_member.permissions.expect(err); let err = "should always be some according to discord docs"; - let bot_permissions = interaction.app_permissions.expect(err); + let mut bot_permissions = interaction.app_permissions.expect(err); + + let channel = interaction.channel.as_ref(); + if channel.is_some_and(|c| is_thread(c.kind)) { + author_permissions.set( + Permissions::SEND_MESSAGES, + author_permissions.send_messages_in_threads(), + ); + bot_permissions.set( + Permissions::SEND_MESSAGES, + bot_permissions.send_messages_in_threads(), + ); + } PermissionsInfo { author_permissions: Some(author_permissions), diff --git a/src/dispatch/permissions/prefix/cache.rs b/src/dispatch/permissions/prefix/cache.rs index bae9e8a94bb..92354768926 100644 --- a/src/dispatch/permissions/prefix/cache.rs +++ b/src/dispatch/permissions/prefix/cache.rs @@ -51,7 +51,14 @@ fn get_bot_permissions( let parent_channel_id = thread.parent_id.expect(err); let parent_channel = guild.channels.get(&parent_channel_id)?; - Some(guild.user_permissions_in(parent_channel, bot_member)) + let mut parent_permissions = guild.user_permissions_in(parent_channel, bot_member); + + parent_permissions.set( + serenity::Permissions::SEND_MESSAGES, + parent_permissions.send_messages_in_threads(), + ); + + Some(parent_permissions) } else { // The message was either: // - Sent in a guild with broken caching diff --git a/src/structs/command.rs b/src/structs/command.rs index 27cfb452e49..e52c64bf5c0 100644 --- a/src/structs/command.rs +++ b/src/structs/command.rs @@ -80,15 +80,21 @@ pub struct Command { /// /// Set to [`serenity::Permissions::empty()`] by default pub default_member_permissions: serenity::Permissions, - /// Permissions which users must have to invoke this command. This is checked internally and - /// works for both prefix commands and slash commands. + /// Permissions which users must have to invoke this command. + /// + /// This is checked internally and works for both prefix commands and slash commands. + /// + /// This also handles the case a message is sent in a thread, in which `SEND_MESSAGES` is set to `SEND_MESSAGES_IN_THREADS`. /// /// Set to [`serenity::Permissions::empty()`] by default pub required_permissions: serenity::Permissions, - /// Permissions without which command execution will fail. You can set this to fail early and - /// give a descriptive error message in case the + /// Permissions without which command execution will fail. + /// + /// You can set this to fail early and give a descriptive error message in case the /// bot hasn't been assigned the minimum permissions by the guild admin. /// + /// This also handles the case a message is sent in a thread, in which `SEND_MESSAGES` is set to `SEND_MESSAGES_IN_THREADS`. + /// /// Set to [`serenity::Permissions::empty()`] by default pub required_bot_permissions: serenity::Permissions, /// If true, only users from the [owners list](crate::FrameworkOptions::owners) may use this