aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZeyla Hellyer <[email protected]>2017-02-12 16:30:47 -0800
committerZeyla Hellyer <[email protected]>2017-02-12 16:30:47 -0800
commit585af231028e46788d689f94e14e110c072a578e (patch)
tree0afa6508ddd11f90d952edd4ce5876f5102c1604
parentRe-export hyper status enums in rest module (diff)
downloadserenity-585af231028e46788d689f94e14e110c072a578e.tar.xz
serenity-585af231028e46788d689f94e14e110c072a578e.zip
Remove most Context methods
Most of the methods in the Context were for interacting with the related ChannelId, but these methods have been re-implemented on ChannelId itself, and is now the preferred (and now only) way to interact with it.
-rw-r--r--src/client/context.rs828
-rw-r--r--src/ext/framework/help_commands.rs18
-rw-r--r--src/ext/framework/mod.rs28
-rw-r--r--src/model/channel.rs21
4 files changed, 52 insertions, 843 deletions
diff --git a/src/client/context.rs b/src/client/context.rs
index ebe6491..d4744a4 100644
--- a/src/client/context.rs
+++ b/src/client/context.rs
@@ -1,76 +1,30 @@
use serde_json::builder::ObjectBuilder;
-use std::io::Read;
use std::sync::{Arc, Mutex};
use super::gateway::Shard;
use super::rest::{self, GuildPagination};
use super::login_type::LoginType;
use typemap::ShareMap;
-use ::utils::builder::{
- CreateEmbed,
- CreateMessage,
- EditChannel,
- EditProfile,
- Search,
-};
+use ::utils::builder::EditProfile;
use ::internal::prelude::*;
use ::model::*;
-#[cfg(feature="extras")]
-use std::ops::ShlAssign;
-
#[cfg(feature="cache")]
use super::CACHE;
/// The context is a general utility struct provided on event dispatches, which
-/// helps with dealing with the current "context" of the event dispatch,
-/// and providing helper methods where possible. The context also acts as a
-/// general high-level interface over the associated [`Shard`] which
-/// received the event, or the low-level [`rest`] module.
-///
-/// For example, when the [`Client::on_message`] handler is dispatched to, the
-/// context will contain the Id of the [`Channel`] that the message was created
-/// for. This allows for using shortcuts like [`say`], which will
-/// post its given argument to the associated channel for you as a [`Message`].
+/// helps with dealing with the current "context" of the event dispatch.
+/// The context also acts as a general high-level interface over the associated
+/// [`Shard`] which received the event, or the low-level [`rest`] module.
///
-/// Additionally, the context contains "shortcuts", like for interacting with
-/// the shard. Methods like [`set_game`] will unlock the shard and perform an
-/// update for you to save a bit of work.
+/// The context contains "shortcuts", like for interacting with the shard.
+/// Methods like [`set_game`] will unlock the shard and perform an update for
+/// you to save a bit of work.
///
/// A context will only live for the event it was dispatched for. After the
/// event handler finished, it is destroyed and will not be re-used.
///
-/// # Automatically using the Cache
-///
-/// The context makes use of the [`Cache`] being global, and will first check
-/// the cache for associated data before hitting the REST API. This is to save
-/// Discord requests, and ultimately save your bot bandwidth and time. This also
-/// acts as a clean interface for retrieving from the cache without needing to
-/// check it yourself first, and then performing a request if it does not exist.
-/// The context ultimately acts as a means to simplify these two operations into
-/// one.
-///
-/// For example, if you are needing information about a
-/// [channel][`GuildChannel`] within a [guild][`Guild`], then you can
-/// use [`get_channel`] to retrieve it. Under most circumstances, the guild and
-/// its channels will be cached within the cache, and `get_channel` will just
-/// pull from the cache. If it does not exist, it will make a request to the
-/// REST API, and then insert a clone of the channel into the cache, returning
-/// you the channel.
-///
-/// In this scenario, now that the cache has the channel, performing the same
-/// request to `get_channel` will instead pull from the cache, as it is now
-/// cached.
-///
-/// [`Channel`]: ../model/enum.Channel.html
-/// [`Client::on_message`]: struct.Client.html#method.on_message
-/// [`Guild`]: ../model/struct.Guild.html
-/// [`Message`]: ../model/struct.Message.html
-/// [`GuildChannel`]: ../model/struct.GuildChannel.html
/// [`Shard`]: gateway/struct.Shard.html
-/// [`Cache`]: ../ext/cache/struct.Cache.html
-/// [`get_channel`]: #method.get_channel
/// [`rest`]: rest/index.html
-/// [`say`]: #method.say
/// [`set_game`]: #method.set_game
#[derive(Clone)]
pub struct Context {
@@ -116,309 +70,6 @@ impl Context {
}
}
- /// Marks the contextual channel as being read up to a certain [`Message`].
- ///
- /// Refer to the documentation for [`rest::ack_message`] for more
- /// information.
- ///
- /// # Errors
- ///
- /// Returns a [`ClientError::InvalidOperationAsBot`] if the current user is
- /// a bot user.
- ///
- /// Returns a [`ClientError::NoChannelId`] if the current context is not
- /// related to a channel.
- ///
- /// [`Channel`]: ../model/enum.Channel.html
- /// [`ChannelId`]: ../model/struct.ChannelId.html
- /// [`ClientError::InvalidOperationAsBot`]: enum.ClientError.html#variant.InvalidOperationAsUser
- /// [`ClientError::NoChannelId`]: enum.ClientError.html#variant.NoChannelId
- /// [`Message`]: ../model/struct.Message.html
- /// [`rest::ack_message`]: rest/fn.ack_message.html
- /// [`say`]: #method.say
- pub fn ack<M: Into<MessageId>>(&self, message_id: M) -> Result<()> {
- if self.login_type == LoginType::User {
- return Err(Error::Client(ClientError::InvalidOperationAsUser));
- }
-
- match self.channel_id {
- Some(channel_id) => channel_id.ack(message_id),
- None => Err(Error::Client(ClientError::NoChannelId)),
- }
- }
-
- /// Broadcasts that you are typing to a channel for the next 5 seconds.
- ///
- /// After 5 seconds, another request must be made to continue broadcasting
- /// that you are typing.
- ///
- /// This should rarely be used for bots, and should likely only be used for
- /// signifying that a long-running command is still being executed.
- ///
- /// Requires the [Send Messages] permission.
- ///
- /// # Examples
- ///
- /// ```rust,ignore
- /// // assuming you are in a context
- /// let _ = context.broadcast_typing();
- /// ```
- ///
- /// # Errors
- ///
- /// Returns a [`ClientError::InvalidOperationAsBot`] if the current user is
- /// a bot user.
- ///
- /// Returns a [`ClientError::NoChannelId`] if the current context is not
- /// related to a channel.
- ///
- /// [`ChannelId`]: ../model/struct.ChannelId.html
- /// [`ClientError::InvalidOperationAsBot`]: enum.ClientError.html#variant.InvalidOperationAsUser
- /// [`ClientError::NoChannelId`]: enum.ClientError.html#variant.NoChannelId
- /// [`say`]: #method.say
- /// [Send Messages]: ../model/permissions/constant.SEND_MESSAGES.html
- pub fn broadcast_typing(&self) -> Result<()> {
- if self.login_type == LoginType::User {
- return Err(Error::Client(ClientError::InvalidOperationAsUser));
- }
-
- match self.channel_id {
- Some(channel_id) => channel_id.broadcast_typing(),
- None => Err(Error::Client(ClientError::NoChannelId)),
- }
- }
-
- /// Creates a [permission overwrite][`PermissionOverwrite`] for either a
- /// single [`Member`] or [`Role`] within the channel.
- ///
- /// Refer to the documentation for [`GuildChannel::create_permission`] for
- /// more information.
- ///
- /// Requires the [Manage Channels] permission.
- ///
- /// # Errors
- ///
- /// Returns a [`ClientError::NoChannelId`] if the current context is not
- /// related to a channel.
- ///
- /// [`ClientError::NoChannelId`]: enum.ClientError.html#variant.NoChannelId
- /// [`GuildChannel::create_permission`]: ../model/struct.GuildChannel.html#method.create_permission
- /// [`Member`]: ../model/struct.Member.html
- /// [`PermissionOverwrite`]: ../model/struct.PermissionOverwrite.html
- /// [`Role`]: ../model/struct.Role.html
- /// [Manage Channels]: ../model/permissions/constant.MANAGE_CHANNELS.html
- pub fn create_permission(&self, target: PermissionOverwrite)
- -> Result<()> {
- match self.channel_id {
- Some(channel_id) => channel_id.create_permission(target),
- None => Err(Error::Client(ClientError::NoChannelId)),
- }
- }
-
- /// React to a [`Message`] with a custom [`Emoji`] or unicode character.
- ///
- /// [`Message::react`] may be a more suited method of reacting in most
- /// cases.
- ///
- /// Requires the [Add Reactions] permission, _if_ the current user is the
- /// first user to perform a react with a certain emoji.
- ///
- /// # Errors
- ///
- /// Returns a [`ClientError::NoChannelId`] if the current context is not
- /// related to a channel.
- ///
- /// [`ClientError::NoChannelId`]: enum.ClientError.html#variant.NoChannelId
- /// [`Emoji`]: ../model/struct.Emoji.html
- /// [`Message`]: ../model/struct.Message.html
- /// [`Message::react`]: ../model/struct.Message.html#method.react
- /// [Add Reactions]: ../model/permissions/constant.ADD_REACTIONS.html
- pub fn create_reaction<M, R>(&self, message_id: M, reaction_type: R)
- -> Result<()> where M: Into<MessageId>, R: Into<ReactionType> {
- match self.channel_id {
- Some(channel_id) => channel_id.create_reaction(message_id, reaction_type),
- None => Err(Error::Client(ClientError::NoChannelId)),
- }
- }
-
- /// Deletes the contextual channel.
- ///
- /// If the channel being deleted is a [`GuildChannel`], then the
- /// [Manage Channels] permission is required.
- ///
- /// # Errors
- ///
- /// Returns a [`ClientError::NoChannelId`] if the current context is not
- /// related to a channel.
- ///
- /// [`Channel`]: ../model/enum.Channel.html
- /// [`ClientError::NoChannelId`]: enum.ClientError.html#variant.NoChannelId
- /// [`Guild`]: ../model/struct.Guild.html
- /// [`GuildChannel`]: ../model/struct.GuildChannel.html
- /// [Manage Channels]: ../model/permissions/constant.MANAGE_CHANNELS.html
- pub fn delete_channel(&self) -> Result<Channel> {
- match self.channel_id {
- Some(channel_id) => channel_id.delete(),
- None => Err(Error::Client(ClientError::NoChannelId)),
- }
- }
-
- /// Deletes a [`Message`] given its Id from the contextual channel.
- ///
- /// Refer to [`Message::delete`] for more information.
- ///
- /// # Examples
- ///
- /// Deleting every message that is received:
- ///
- /// ```rust,ignore
- /// use serenity::Client;
- /// use std::env;
- ///
- /// let client = Client::login_bot(&env::var("DISCORD_BOT_TOKEN").unwrap());
- /// client.on_message(|ctx, message| {
- /// ctx.delete_message(message);
- /// });
- /// ```
- ///
- /// (in practice, please do not do this)
- ///
- /// # Errors
- ///
- /// Returns a [`ClientError::NoChannelId`] if the current context is not
- /// related to a channel.
- ///
- /// [`ClientError::NoChannelId`]: enum.ClientError.html#variant.NoChannelId
- /// [`Message`]: ../model/struct.Message.html
- /// [`Message::delete`]: ../model/struct.Message.html#method.delete
- /// [Manage Messages]: ../model/permissions/constant.MANAGE_MESSAGES.html
- pub fn delete_message<M: Into<MessageId>>(&self, message_id: M) -> Result<()> {
- match self.channel_id {
- Some(channel_id) => channel_id.delete_message(message_id),
- None => Err(Error::Client(ClientError::NoChannelId)),
- }
- }
-
- /// Deletes all messages by Ids from the given vector in the given channel.
- ///
- /// The minimum amount of messages is 2 and the maximum amount is 100.
- ///
- /// Requires the [Manage Messages] permission.
- ///
- /// **Note**: This uses bulk delete endpoint which is not available
- /// for user accounts.
- ///
- /// **Note**: Messages that are older than 2 weeks can't be deleted using this method.
- ///
- /// # Errors
- ///
- /// Returns a [`ClientError::NoChannelId`] if the current context is not
- /// related to a channel.
- ///
- /// Returns a [`ClientError::InvalidOperationAsUser`] if the current user is
- /// not a bot user.
- ///
- /// [`ClientError::InvalidOperationAsUser`]: enum.ClientError.html#variant.InvalidOperationAsUser
- /// [`ClientError::NoChannelId`]: enum.ClientError.html#variant.NoChannelId
- /// [Manage Messages]: ../model/permissions/constant.MANAGE_MESSAGES.html
- pub fn delete_messages(&self, message_ids: &[MessageId]) -> Result<()> {
- if self.login_type == LoginType::User {
- return Err(Error::Client(ClientError::InvalidOperationAsUser))
- }
-
- match self.channel_id {
- Some(channel_id) => channel_id.delete_messages(message_ids),
- None => Err(Error::Client(ClientError::NoChannelId)),
- }
- }
-
- /// Deletes all permission overrides in the contextual channel from a member
- /// or role.
- ///
- /// **Note**: Requires the [Manage Channel] permission.
- ///
- /// # Errors
- ///
- /// Returns a [`ClientError::NoChannelId`] if the current context is not
- /// related to a channel.
- ///
- /// [`ClientError::NoChannelId`]: enum.ClientError.html#variant.NoChannelId
- /// [Manage Channel]: ../model/permissions/constant.MANAGE_CHANNELS.html
- #[inline]
- pub fn delete_permission(&self, permission_type: PermissionOverwriteType) -> Result<()> {
- match self.channel_id {
- Some(channel_id) => channel_id.delete_permission(permission_type),
- None => Err(Error::Client(ClientError::NoChannelId)),
- }
- }
-
- /// Deletes the given [`Reaction`] from the contextual channel.
- ///
- /// **Note**: Requires the [Manage Messages] permission, _if_ the current
- /// user did not perform the reaction.
- ///
- /// # Errors
- ///
- /// Returns a [`ClientError::NoChannelId`] if the current context is not
- /// related to a channel.
- ///
- /// [`ClientError::NoChannelId`]: enum.ClientError.html#variant.NoChannelId
- /// [`Reaction`]: ../model/struct.Reaction.html
- /// [Manage Messages]: ../model/permissions/constant.MANAGE_MESSAGES.html
- pub fn delete_reaction<M, R>(&self, message_id: M, user_id: Option<UserId>, reaction_type: R)
- -> Result<()> where M: Into<MessageId>, R: Into<ReactionType> {
- match self.channel_id {
- Some(channel_id) => channel_id.delete_reaction(message_id, user_id, reaction_type),
- None => Err(Error::Client(ClientError::NoChannelId)),
- }
- }
-
- /// Edits the settings of a [`Channel`], optionally setting new values.
- ///
- /// Refer to `EditChannel`'s documentation for its methods.
- ///
- /// Requires the [Manage Channel] permission.
- ///
- /// # Examples
- ///
- /// Change a voice channel's name and bitrate:
- ///
- /// ```rust,ignore
- /// context.edit_channel(channel_id, |c| c
- /// .name("test")
- /// .bitrate(64000));
- /// ```
- ///
- /// # Errors
- ///
- /// Returns a [`ClientError::NoChannelId`] if the current context is not
- /// related to a guild channel.
- ///
- /// [`Channel`]: ../model/enum.Channel.html
- /// [`ClientError::NoChannelId`]: enum.ClientError.html#variant.NoChannelId
- /// [Manage Channel]: ../model/permissions/constant.MANAGE_CHANNEL.html
- pub fn edit_channel<F>(&self, f: F) -> Result<GuildChannel>
- where F: FnOnce(EditChannel) -> EditChannel {
- let channel_id = match self.channel_id {
- Some(channel_id) => channel_id,
- None => return Err(Error::Client(ClientError::NoChannelId)),
- };
-
- #[cfg(feature="cache")]
- {
-
- if let Channel::Guild(ref channel) = channel_id.get()? {
- let ch = channel.read().unwrap();
-
- if ch.kind != ChannelType::Text && ch.kind != ChannelType::Voice {
- return Err(Error::Client(ClientError::UnexpectedChannelType(ch.kind)));
- }
- }
- }
-
- channel_id.edit(f)
- }
-
/// Edits the current user's profile settings.
///
/// Refer to `EditProfile`'s documentation for its methods.
@@ -458,440 +109,6 @@ impl Context {
rest::edit_profile(edited)
}
- /// Edits a [`Message`] given its Id and the Id of the channel it belongs
- /// to.
- ///
- /// Refer to [`Channel::edit_message`] for more information.
- ///
- /// **Note**: Requires that the current user be the author of the message.
- ///
- /// # Errors
- ///
- /// Returns a [`ClientError::NoChannelId`] if the current context is not
- /// related to a channel.
- ///
- /// [`Channel::edit_message`]: ../model/enum.Channel.html#method.edit_message
- /// [`ClientError::NoChannelId`]: enum.ClientError.html#variant.NoChannelId
- /// [`Message`]: ../model/struct.Message.html
- pub fn edit_message<F, M>(&self, message_id: M, text: &str, f: F) -> Result<Message>
- where F: FnOnce(CreateEmbed) -> CreateEmbed, M: Into<MessageId> {
- match self.channel_id {
- Some(channel_id) => channel_id.edit_message(message_id, text, f),
- None => Err(Error::Client(ClientError::NoChannelId)),
- }
- }
-
- /// Gets a fresh version of the channel over the REST API.
- ///
- /// # Errors
- ///
- /// Returns a [`ClientError::NoChannelId`] if the current context is not
- /// related to a channel.
- ///
- /// [`ClientError::NoChannelId`]: enum.ClientError.html#variant.NoChannelId
- pub fn get_channel(&self) -> Result<Channel> {
- match self.channel_id {
- Some(channel_id) => channel_id.get(),
- None => Err(Error::Client(ClientError::NoChannelId)),
- }
- }
-
- /// Gets all of a [`GuildChannel`]'s invites.
- ///
- /// Requires the [Manage Guild] permission.
- ///
- /// # Errors
- ///
- /// Returns a [`ClientError::NoChannelId`] if the current context is not
- /// related to a channel.
- ///
- /// [`ClientError::NoChannelId`]: enum.ClientError.html#variant.NoChannelId
- /// [`GuildChannel`]: ../model/struct.GuildChannel.html
- /// [Manage Guild]: ../model/permissions/constant.MANAGE_GUILD.html
- pub fn get_channel_invites(&self) -> Result<Vec<RichInvite>> {
- match self.channel_id {
- Some(channel_id) => channel_id.get_invites(),
- None => Err(Error::Client(ClientError::NoChannelId)),
- }
- }
-
- /// Gets a paginated list of guilds that the current user is in.
- ///
- /// The `limit` has a maximum value of 100.
- ///
- /// See also: [`CurrentUser::guilds`].
- ///
- /// # Examples
- ///
- /// Get the first 10 guilds after the current [`Message`]'s guild's Id:
- ///
- /// ```rust,ignore
- /// use serenity::client::rest::GuildPagination;
- ///
- /// // assuming you are in a context
- ///
- /// let guild_id = message.guild_id().unwrap();
- /// context.get_guilds(GuildPagination::After(guild_id, 10)).unwrap();
- /// ```
- ///
- /// [`CurrentUser::guilds`]: ../model/struct.CurrentUser.html#method.guilds
- /// [`Message`]: ../model/struct.Message.html
- #[inline]
- pub fn get_guilds(&self, target: GuildPagination, limit: u8) -> Result<Vec<GuildInfo>> {
- rest::get_guilds(target, limit as u64)
- }
-
- /// Gets a single [`Message`] from the contextual channel.
- ///
- /// Requires the [Read Message History] permission.
- ///
- /// # Errors
- ///
- /// Returns a [`ClientError::InvalidOperationAsUser`] if the current user is
- /// not a user account.
- ///
- /// Returns a [`ClientError::NoChannelId`] if the current context is not
- /// related to a channel.
- ///
- /// [`ClientError::InvalidOperationAsUser`]: enum.ClientError.html#variant.InvalidOperationAsUser
- /// [`ClientError::NoChannelId`]: enum.ClientError.html#variant.NoChannelId
- /// [`Message`]: ../model/struct.Message.html
- /// [Read Message History]: ../model/permissions/constant.READ_MESSAGE_HISTORY.html
- pub fn get_message<M: Into<MessageId>>(&self, message_id: M) -> Result<Message> {
- if self.login_type == LoginType::User {
- return Err(Error::Client(ClientError::InvalidOperationAsUser))
- }
-
- match self.channel_id {
- Some(channel_id) => channel_id.get_message(message_id),
- None => Err(Error::Client(ClientError::NoChannelId)),
- }
- }
-
- /// Gets the list of [`User`]s who have reacted to a [`Message`] with a
- /// certain [`Emoji`].
- ///
- /// The default `limit` is `50` - specify otherwise to receive a different
- /// maximum number of users. The maximum that may be retrieve at a time is
- /// `100`, if a greater number is provided then it is automatically reduced.
- ///
- /// The optional `after` attribute is to retrieve the users after a certain
- /// user. This is useful for pagination.
- ///
- /// **Note**: Requires the [Read Message History] permission.
- ///
- /// # Errors
- ///
- /// Returns a [`ClientError::NoChannelId`] if the current context is not
- /// related to a channel.
- ///
- /// [`ClientError::NoChannelId`]: enum.ClientError.html#variant.NoChannelId
- /// [`Emoji`]: ../model/struct.Emoji.html
- /// [`Message`]: ../model/struct.Message.html
- /// [`User`]: ../model/struct.User.html
- /// [Read Message History]: ../model/permissions/constant.READ_MESSAGE_HISTORY.html
- pub fn get_reaction_users<M, R, U>(&self,
- message_id: M,
- reaction_type: R,
- limit: Option<u8>,
- after: Option<U>)
- -> Result<Vec<User>> where M: Into<MessageId>, R: Into<ReactionType>, U: Into<UserId> {
- match self.channel_id {
- Some(c) => c.get_reaction_users(message_id, reaction_type, limit, after),
- None => Err(Error::Client(ClientError::NoChannelId)),
- }
- }
-
- /// Pins a [`Message`] in the specified [`Channel`] by its Id.
- ///
- /// Requires the [Manage Messages] permission.
- ///
- /// # Errors
- ///
- /// Returns a [`ClientError::NoChannelId`] if the current context is not
- /// related to a channel.
- ///
- /// [`Channel`]: ../model/enum.Channel.html
- /// [`ClientError::NoChannelId`]: enum.ClientError.html#variant.NoChannelId
- /// [`Message`]: ../model/struct.Message.html
- /// [Manage Messages]: ../model/permissions/constant.MANAGE_MESSAGES.html
- pub fn pin<M: Into<MessageId>>(&self, message_id: M) -> Result<()> {
- match self.channel_id {
- Some(channel_id) => channel_id.pin(message_id),
- None => Err(Error::Client(ClientError::NoChannelId)),
- }
- }
-
- /// Gets the list of [`Message`]s which are pinned to the specified
- /// [`Channel`].
- ///
- /// [`Channel`]: ../model/enum.Channel.html
- /// [`Message`]: ../model/struct.Message.html
- pub fn pins(&self) -> Result<Vec<Message>> {
- match self.channel_id {
- Some(channel_id) => channel_id.pins(),
- None => Err(Error::Client(ClientError::NoChannelId)),
- }
- }
-
- /// Sends a message with just the given message content in the channel that
- /// a message was received from.
- ///
- /// # Supported Events
- ///
- /// This will only work through the context of one of the following event
- /// dispatches:
- ///
- /// - [`ChannelCreate`][`Event::ChannelCreate`]
- /// - [`ChannelPinsAck`][`Event::ChannelPinsAck`]
- /// - [`ChannelPinsUpdate`][`Event::ChannelPinsUpdate`]
- /// - [`ChannelRecipientAdd`][`Event::ChannelRecipientAdd`]
- /// - [`ChannelRecipientRemove`][`Event::ChannelRecipientRemove`]
- /// - [`ChannelUpdate`][`Event::ChannelUpdate`]
- /// - [`MessageAck`][`Event::MessageAck`]
- /// - [`MessageDelete`][`Event::MessageDelete`]
- /// - [`MessageDeleteBulk`][`Event::MessageDeleteBulk`]
- /// - [`MessageUpdate`][`Event::MessageUpdate`]
- /// - [`ReactionAdd`][`Event::ReactionAdd`]
- /// - [`ReactionRemove`][`Event::ReactionRemove`]
- /// - [`ReactionRemoveAll`][`Event::ReactionRemoveAll`]
- ///
- /// # Errors
- ///
- /// Returns a [`ClientError::MessageTooLong`] if the content of the message
- /// is over the above limit, containing the number of unicode code points
- /// over the limit.
- ///
- /// Returns a [`ClientError::NoChannelId`] when there is no [`ChannelId`]
- /// directly available; i.e. when not under the context of one of the above
- /// events.
- ///
- /// [`ChannelId`]: ../model/struct.ChannelId.html
- /// [`ClientError::MessageTooLong`]: enum.ClientError.html#variant.MessageTooLong
- /// [`ClientError::NoChannelId`]: enum.ClientError.html#NoChannelId
- /// [`Event::ChannelCreate`]: ../model/event/enum.Event.html#variant.ChannelCreate
- /// [`Event::ChannelPinsAck`]: ../model/event/enum.Event.html#variant.ChannelPinsAck
- /// [`Event::ChannelPinsUpdate`]: ../model/event/enum.Event.html#variant.ChannelPinsUpdate
- /// [`Event::ChannelRecipientAdd`]: ../model/event/enum.Event.html#variant.ChannelRecipientAdd
- /// [`Event::ChannelRecipientRemove`]: ../model/event/enum.Event.html#variant.ChannelRecipientRemove
- /// [`Event::ChannelUpdate`]: ../model/event/enum.Event.html#variant.ChannelUpdate
- /// [`Event::MessageAck`]: ../model/event/enum.Event.html#variant.MessageAck
- /// [`Event::MessageDelete`]: ../model/event/enum.Event.html#variant.MessageDelete
- /// [`Event::MessageDeleteBulk`]: ../model/event/enum.Event.html#variant.MessageDeleteBulk
- /// [`Event::MessageUpdate`]: ../model/event/enum.Event.html#variant.MessageUpdate
- /// [`Event::ReactionAdd`]: ../model/event/enum.Event.html#variant.ReactionAdd
- /// [`Event::ReactionRemove`]: ../model/event/enum.Event.html#variant.ReactionRemove
- /// [`Event::ReactionRemoveAll`]: ../model/event/enum.Event.html#variant.ReactionRemoveAll
- /// [`Message`]: ../model/struct.Message.html
- pub fn say(&self, content: &str) -> Result<Message> {
- match self.channel_id {
- Some(channel_id) => channel_id.send_message(|m| m.content(content)),
- None => Err(Error::Client(ClientError::NoChannelId)),
- }
- }
-
- /// Adds a string to message queue, which is sent joined by a newline
- /// when context goes out of scope.
- ///
- /// **Note**: Only works in a context where a channel is present. Refer to
- /// [`say`] for a list of events where this is applicable.
- ///
- /// [`say`]: #method.say
- pub fn queue(&mut self, content: &str) -> &mut Self {
- self.queue.push('\n');
- self.queue.push_str(content);
-
- self
- }
-
- /// Searches a [`Channel`]'s messages by providing query parameters via the
- /// search builder.
- ///
- /// Refer to the documentation for the [`Search`] builder for restrictions
- /// and defaults parameters, as well as potentially advanced usage.
- ///
- /// **Note**: Bot users can not search.
- ///
- /// # Examples
- ///
- /// Refer to the [`Search`] builder's documentation for examples,
- /// specifically the section on [searching a channel][search channel].
- ///
- /// # Errors
- ///
- /// If the `cache` is enabled, returns a
- /// [`ClientError::InvalidOperationAsBot`] if the current user is a bot.
- ///
- /// [`ClientError::InvalidOperationAsBot`]: enum.ClientError.html#variant.InvalidOperationAsBot
- /// [`Channel`]: ../model/enum.Channel.html
- /// [`Search`]: ../utils/builder/struct.Search.html
- /// [search channel]: ../utils/builder/struct.Search.html#searching-a-channel
- pub fn search_channel<F>(&self, f: F) -> Result<SearchResult>
- where F: FnOnce(Search) -> Search {
- let channel_id = match self.channel_id {
- Some(channel_id) => channel_id,
- None => return Err(Error::Client(ClientError::NoChannelId)),
- };
-
- #[cfg(feature="cache")]
- {
- if CACHE.read().unwrap().user.bot {
- return Err(Error::Client(ClientError::InvalidOperationAsBot));
- }
- }
-
- channel_id.search(f)
- }
-
- /// Sends a file along with optional message contents. The filename _must_
- /// be specified.
- ///
- /// Message contents may be passed by using the [`CreateMessage::content`]
- /// method.
- ///
- /// An embed can _not_ be sent when sending a file. If you set one, it will
- /// be automatically removed.
- ///
- /// Requires the [Attach Files] and [Send Messages] permissions are required.
- ///
- /// **Note**: Message contents must be under 2000 unicode code points.
- ///
- /// # Errors
- ///
- /// If the content of the message is over the above limit, then a
- /// [`ClientError::MessageTooLong`] will be returned, containing the number
- /// of unicode code points over the limit.
- ///
- /// [`ClientError::MessageTooLong`]: enum.ClientError.html#variant.MessageTooLong
- /// [`CreateMessage::content`]: ../utils/builder/struct.CreateMessage.html#method.content
- /// [`GuildChannel`]: ../model/struct.GuildChannel.html
- /// [Attach Files]: ../model/permissions/constant.ATTACH_FILES.html
- /// [Send Messages]: ../model/permissions/constant.SEND_MESSAGES.html
- pub fn send_file<F, R>(&self, file: R, filename: &str, f: F) -> Result<Message>
- where F: FnOnce(CreateMessage) -> CreateMessage, R: Read {
- match self.channel_id {
- Some(channel_id) => channel_id.send_file(file, filename, f),
- None => Err(Error::Client(ClientError::NoChannelId)),
- }
- }
-
- /// Sends a message to a [`Channel`].
- ///
- /// Refer to the documentation for [`CreateMessage`] for more information
- /// regarding message restrictions and requirements.
- ///
- /// **Note**: Message contents must be under 2000 unicode code points.
- ///
- /// Requires the [Send Messages] permission is required.
- ///
- /// # Example
- ///
- /// Send a message with just the content `test`:
- ///
- /// ```rust,ignore
- /// // assuming you are in a context
- /// let _ = context.send_message(|f| f.content("test"));
- /// ```
- ///
- /// Send a message on `!ping` with a very descriptive [`Embed`]. This sends
- /// a message content of `"Pong! Here's some info"`, with an embed with the
- /// following attributes:
- ///
- /// - Dark gold in colour;
- /// - A description of `"Information about the message just posted"`;
- /// - A title of `"Message Information"`;
- /// - A URL of `"https://rust-lang.org"`;
- /// - An [author structure] containing an icon and the user's name;
- /// - An inline [field structure] containing the message's content with a
- /// label;
- /// - An inline field containing the channel's name with a label;
- /// - A footer containing the current user's icon and name, saying that the
- /// information was generated by them.
- ///
- /// ```rust,ignore
- /// use serenity::client::{CACHE, Client, Context};
- /// use serenity::model::{Channel, Message};
- /// use serenity::utils::Colour;
- /// use std::env;
- ///
- /// let mut client = Client::login_bot(&env::var("DISCORD_TOKEN").unwrap());
- /// client.with_framework(|f| f
- /// .configure(|c| c.prefix("~"))
- /// .on("ping", ping));
- ///
- /// client.on_ready(|_context, ready| {
- /// println!("{} is connected!", ready.user.name);
- /// });
- ///
- /// let _ = client.start();
- ///
- /// command!(ping(context, message) {
- /// let cache = CACHE.read().unwrap();
- /// let channel = cache.get_guild_channel(message.channel_id);
- ///
- /// let _ = context.send_message(|m| m
- /// .content("Pong! Here's some info")
- /// .embed(|e| e
- /// .colour(Colour::dark_gold())
- /// .description("Information about the message just posted")
- /// .title("Message information")
- /// .url("https://rust-lang.org")
- /// .author(|mut a| {
- /// a = a.name(&message.author.name);
- ///
- /// if let Some(avatar) = message.author.avatar_url() {
- /// a = a.icon_url(&avatar);
- /// }
- ///
- /// a
- /// })
- /// .field(|f| f
- /// .inline(true)
- /// .name("Message content:")
- /// .value(&message.content))
- /// .field(|f| f
- /// .inline(true)
- /// .name("Channel name:")
- /// .value(&channel.map_or_else(|| "Unknown", |c| &c.name)))
- /// .footer(|mut f| {
- /// f = f.text(&format!("Generated by {}", cache.user.name));
- ///
- /// if let Some(avatar) = cache.user.avatar_url() {
- /// f = f.icon_url(&avatar);
- /// }
- ///
- /// f
- /// })));
- ///
- /// Ok(())
- /// });
- /// ```
- ///
- /// Note that for most use cases, your embed layout will _not_ be this ugly.
- /// This is an example of a very involved and conditional embed.
- ///
- /// # Errors
- ///
- /// Returns a [`ClientError::MessageTooLong`] if the content of the message
- /// is over the above limit, containing the number of unicode code points
- /// over the limit.
- ///
- /// [`Channel`]: ../model/enum.Channel.html
- /// [`ClientError::MessageTooLong`]: enum.ClientError.html#variant.MessageTooLong
- /// [`CreateMessage`]: ../utils/builder/struct.CreateMessage.html
- /// [`Embed`]: ../model/struct.Embed.html
- /// [`GuildChannel`]: ../model/struct.GuildChannel.html
- /// [Send Messages]: ../model/permissions/constant.SEND_MESSAGES.html
- /// [author structure]: ../utils/builder/struct.CreateEmbedAuthor.html
- /// [field structure]: ../utils/builder/struct.CreateEmbedField.html
- pub fn send_message<F>(&self, f: F) -> Result<Message>
- where F: FnOnce(CreateMessage) -> CreateMessage {
- match self.channel_id {
- Some(channel_id) => channel_id.send_message(f),
- None => Err(Error::Client(ClientError::NoChannelId)),
- }
- }
-
/// Sets the current user as being [`Online`]. This maintains the current
/// game and `afk` setting.
///
@@ -1025,35 +242,4 @@ impl Context {
.unwrap()
.set_presence(game, status, afk)
}
-
- /// Unpins a [`Message`] in the contextual channel given by its Id.
- ///
- /// Requires the [Manage Messages] permission.
- ///
- /// [`Channel`]: ../model/enum.Channel.html
- /// [`Message`]: ../model/struct.Message.html
- /// [Manage Messages]: ../model/permissions/constant.MANAGE_MESSAGES.html
- pub fn unpin<M: Into<MessageId>>(&self, message_id: M) -> Result<()> {
- match self.channel_id {
- Some(channel_id) => channel_id.unpin(message_id),
- None => Err(Error::Client(ClientError::NoChannelId)),
- }
- }
-}
-
-impl Drop for Context {
- /// Combines and sends all queued messages.
- fn drop(&mut self) {
- if !self.queue.is_empty() {
- let _ = self.say(&self.queue);
- }
- }
-}
-
-/// Allows the `<<=` operator to be used to queue messages.
-#[cfg(feature="extras")]
-impl<'a> ShlAssign<&'a str> for &'a mut Context {
- fn shl_assign(&mut self, rhs: &str) {
- self.queue(rhs);
- }
}
diff --git a/src/ext/framework/help_commands.rs b/src/ext/framework/help_commands.rs
index 863f3fd..d5e6ae2 100644
--- a/src/ext/framework/help_commands.rs
+++ b/src/ext/framework/help_commands.rs
@@ -8,7 +8,9 @@ use ::model::Message;
use ::utils::Colour;
fn error_embed(ctx: &mut Context, input: &str) {
- let _ = ctx.send_message(|m| m
+ let _ = ctx.channel_id
+ .unwrap()
+ .send_message(|m| m
.embed(|e| e
.colour(Colour::dark_red())
.description(input)));
@@ -63,7 +65,7 @@ pub fn with_embeds(ctx: &mut Context,
return Ok(());
}
- let _ = ctx.send_message(|m| {
+ let _ = ctx.channel_id.unwrap().send_message(|m| {
m.embed(|e| {
let mut embed = e.colour(Colour::rosewater())
.title(command_name);
@@ -115,7 +117,7 @@ pub fn with_embeds(ctx: &mut Context,
return Ok(());
}
- let _ = ctx.send_message(|m| m
+ let _ = ctx.channel_id.unwrap().send_message(|m| m
.embed(|mut e| {
e = e.colour(Colour::rosewater())
.description("To get help with an individual command, pass its \
@@ -174,7 +176,7 @@ pub fn plain(ctx: &mut Context,
found = Some((command_name, cmd));
},
CommandOrAlias::Alias(ref name) => {
- let _ = ctx.say(&format!("Did you mean {:?}?", name));
+ let _ = ctx.channel_id.unwrap().say(&format!("Did you mean {:?}?", name));
return Ok(());
}
}
@@ -183,7 +185,7 @@ pub fn plain(ctx: &mut Context,
if let Some((command_name, command)) = found {
if !command.help_available {
- let _ = ctx.say("**Error**: No help available.");
+ let _ = ctx.channel_id.unwrap().say("**Error**: No help available.");
return Ok(());
}
@@ -215,13 +217,13 @@ pub fn plain(ctx: &mut Context,
});
result.push_str("\n");
- let _ = ctx.say(&result);
+ let _ = ctx.channel_id.unwrap().say(&result);
return Ok(());
}
}
- let _ = ctx.say(&format!("**Error**: Command `{}` not found.", name));
+ let _ = ctx.channel_id.unwrap().say(&format!("**Error**: Command `{}` not found.", name));
return Ok(());
}
@@ -254,7 +256,7 @@ pub fn plain(ctx: &mut Context,
result.push('\n');
}
- let _ = ctx.say(&result);
+ let _ = ctx.channel_id.unwrap().say(&result);
Ok(())
}
diff --git a/src/ext/framework/mod.rs b/src/ext/framework/mod.rs
index 30a5c8f..3c926a7 100644
--- a/src/ext/framework/mod.rs
+++ b/src/ext/framework/mod.rs
@@ -349,7 +349,7 @@ impl Framework {
if !is_owner {
if command.owners_only {
if let Some(ref message) = self.configuration.invalid_permission_message {
- let _ = context.say(message);
+ let _ = context.channel_id.unwrap().say(message);
}
return;
@@ -363,7 +363,7 @@ impl Framework {
{
if !self.configuration.allow_dm && message.is_private() {
if let Some(ref message) = self.configuration.no_dm_message {
- let _ = context.say(message);
+ let _ = context.channel_id.unwrap().say(message);
}
return;
@@ -372,7 +372,7 @@ impl Framework {
if self.configuration.blocked_users.contains(&message.author.id) {
if let Some(ref message) = self.configuration.blocked_user_message {
- let _ = context.say(message);
+ let _ = context.channel_id.unwrap().say(message);
}
return;
@@ -383,7 +383,7 @@ impl Framework {
if let Some(ref message) = self.configuration.command_disabled_message {
let msg = message.replace("%command%", &to_check);
- let _ = context.say(&msg);
+ let _ = context.channel_id.unwrap().say(&msg);
}
return;
@@ -396,7 +396,7 @@ impl Framework {
if let Some(ref message) = self.configuration.rate_limit_message {
let msg = message.replace("%time%", &rate_limit.to_string());
- let _ = context.say(&msg);
+ let _ = context.channel_id.unwrap().say(&msg);
}
return;
@@ -416,7 +416,7 @@ impl Framework {
if let Some(guild_id) = guild_id {
if self.configuration.blocked_guilds.contains(&guild_id) {
if let Some(ref message) = self.configuration.blocked_guild_message {
- let _ = context.say(message);
+ let _ = context.channel_id.unwrap().say(message);
}
return;
@@ -425,7 +425,7 @@ impl Framework {
if let Some(guild) = guild_id.find() {
if self.configuration.blocked_users.contains(&guild.read().unwrap().owner_id) {
if let Some(ref message) = self.configuration.blocked_guild_message {
- let _ = context.say(message);
+ let _ = context.channel_id.unwrap().say(message);
}
return;
@@ -436,14 +436,14 @@ impl Framework {
if message.is_private() {
if command.guild_only {
if let Some(ref message) = self.configuration.no_guild_message {
- let _ = context.say(message);
+ let _ = context.channel_id.unwrap().say(message);
}
return;
}
} else if command.dm_only {
if let Some(ref message) = self.configuration.no_dm_message {
- let _ = context.say(message);
+ let _ = context.channel_id.unwrap().say(message);
}
return;
@@ -453,7 +453,7 @@ impl Framework {
for check in &command.checks {
if !(check)(&mut context, &message) {
if let Some(ref message) = self.configuration.invalid_check_message {
- let _ = context.say(message);
+ let _ = context.channel_id.unwrap().say(message);
}
continue 'outer;
@@ -481,7 +481,7 @@ impl Framework {
let msg = message.replace("%min%", &x.to_string())
.replace("%given%", &args.len().to_string());
- let _ = context.say(&msg);
+ let _ = context.channel_id.unwrap().say(&msg);
}
return;
@@ -494,7 +494,7 @@ impl Framework {
let msg = message.replace("%max%", &x.to_string())
.replace("%given%", &args.len().to_string());
- let _ = context.say(&msg);
+ let _ = context.channel_id.unwrap().say(&msg);
}
return;
@@ -538,7 +538,7 @@ impl Framework {
if !permissions_fulfilled {
if let Some(ref message) = self.configuration.invalid_permission_message {
- let _ = context.say(message);
+ let _ = context.channel_id.unwrap().say(message);
}
return;
@@ -555,7 +555,7 @@ impl Framework {
let result = match command.exec {
CommandType::StringResponse(ref x) => {
- let _ = &mut context.say(x);
+ let _ = &mut context.channel_id.unwrap().say(x);
Ok(())
},
diff --git a/src/model/channel.rs b/src/model/channel.rs
index e6ebb27..834fa9b 100644
--- a/src/model/channel.rs
+++ b/src/model/channel.rs
@@ -733,6 +733,27 @@ impl ChannelId {
rest::get_pins(self.0)
}
+ /// Sends a message with just the given message content in the channel that
+ /// a message was received from.
+ ///
+ /// # Errors
+ ///
+ /// Returns a [`ClientError::MessageTooLong`] if the content of the message
+ /// is over the above limit, containing the number of unicode code points
+ /// over the limit.
+ ///
+ /// Returns a [`ClientError::NoChannelId`] when there is no [`ChannelId`]
+ /// directly available; i.e. when not under the context of one of the above
+ /// events.
+ ///
+ /// [`ChannelId`]: ../model/struct.ChannelId.html
+ /// [`ClientError::MessageTooLong`]: enum.ClientError.html#variant.MessageTooLong
+ /// [`ClientError::NoChannelId`]: enum.ClientError.html#NoChannelId
+ #[inline]
+ pub fn say(&self, content: &str) -> Result<Message> {
+ self.send_message(|m| m.content(content))
+ }
+
/// Searches the channel's messages by providing query parameters via the
/// search builder.
///