aboutsummaryrefslogtreecommitdiff
path: root/src/model/channel.rs
diff options
context:
space:
mode:
authorAustin Hellyer <[email protected]>2017-01-23 12:16:06 -0800
committerAustin Hellyer <[email protected]>2017-01-23 12:16:06 -0800
commit651c618f17cb92d3ea9bbd1d5f5c92a015ff64e0 (patch)
treedcf452e8fe73411af331678a769cb769a32dd12e /src/model/channel.rs
parentFix no-framework compilation (diff)
downloadserenity-651c618f17cb92d3ea9bbd1d5f5c92a015ff64e0.tar.xz
serenity-651c618f17cb92d3ea9bbd1d5f5c92a015ff64e0.zip
Switch to a mostly-fully OOP approach
The context is now strictly in relation to the context of the current channel related to the event, if any. See Context::say for a list of events that the context can be used for.
Diffstat (limited to 'src/model/channel.rs')
-rw-r--r--src/model/channel.rs1363
1 files changed, 1240 insertions, 123 deletions
diff --git a/src/model/channel.rs b/src/model/channel.rs
index a773cc7..bda26e5 100644
--- a/src/model/channel.rs
+++ b/src/model/channel.rs
@@ -1,5 +1,9 @@
+use hyper::Client as HyperClient;
+use serde_json::builder::ObjectBuilder;
use std::borrow::Cow;
use std::fmt::{self, Write};
+use std::io::Read;
+use std::mem;
use super::utils::{
decode_id,
into_map,
@@ -8,34 +12,29 @@ use super::utils::{
remove,
};
use super::*;
+use ::client::rest;
use ::constants;
use ::internal::prelude::*;
+use ::utils::builder::{
+ CreateEmbed,
+ CreateInvite,
+ CreateMessage,
+ EditChannel,
+ GetMessages,
+ Search
+};
use ::utils::decode_array;
-#[cfg(feature="methods")]
-use hyper::Client as HyperClient;
-#[cfg(feature="methods")]
-use serde_json::builder::ObjectBuilder;
-#[cfg(feature="methods")]
-use std::io::Read;
-#[cfg(feature="methods")]
-use std::mem;
-#[cfg(all(feature="cache", feature="methods"))]
+#[cfg(feature="cache")]
use super::utils;
-
-#[cfg(all(feature="cache", feature="methods"))]
+#[cfg(feature="cache")]
use ::client::CACHE;
-#[cfg(feature="methods")]
-use ::client::rest;
-#[cfg(all(feature="cache", feature="methods"))]
+#[cfg(feature="cache")]
use ::ext::cache::ChannelRef;
-#[cfg(feature="methods")]
-use ::utils::builder::{CreateEmbed, CreateInvite, EditChannel, Search};
impl Attachment {
/// If this attachment is an image, then a tuple of the width and height
/// in pixels is returned.
- #[cfg(feature="methods")]
pub fn dimensions(&self) -> Option<(u64, u64)> {
if let (Some(width), Some(height)) = (self.width, self.height) {
Some((width, height))
@@ -110,7 +109,6 @@ impl Attachment {
/// [`Error::Hyper`]: ../enum.Error.html#variant.Hyper
/// [`Error::Io`]: ../enum.Error.html#variant.Io
/// [`Message`]: struct.Message.html
- #[cfg(feature="methods")]
pub fn download(&self) -> Result<Vec<u8>> {
let hyper = HyperClient::new();
let mut response = hyper.get(&self.url).send()?;
@@ -123,6 +121,50 @@ impl Attachment {
}
impl Channel {
+ /// Marks the channel as being read up to a certain [`Message`].
+ ///
+ /// Refer to the documentation for [`rest::ack_message`] for more
+ /// information.
+ ///
+ /// # Errors
+ ///
+ /// If the `cache` is enabled, returns a
+ /// [`ClientError::InvalidOperationAsBot`] if the current user is a bot
+ /// user.
+ ///
+ /// [`Channel`]: enum.Channel.html
+ /// [`ClientError::InvalidOperationAsBot`]: ../client/enum.ClientError.html#variant.InvalidOperationAsUser
+ /// [`Message`]: struct.Message.html
+ /// [`rest::ack_message`]: rest/fn.ack_message.html
+ pub fn ack<M: Into<MessageId>>(&self, message_id: M) -> Result<()> {
+ #[cfg(feature="cache")]
+ {
+ if CACHE.read().unwrap().user.bot {
+ return Err(Error::Client(ClientError::InvalidOperationAsBot));
+ }
+ }
+
+ self.id().ack(message_id)
+ }
+
+ /// 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.
+ ///
+ /// [`Emoji`]: struct.Emoji.html
+ /// [`Message`]: struct.Message.html
+ /// [`Message::react`]: struct.Message.html#method.react
+ /// [Add Reactions]: permissions/constant.ADD_REACTIONS.html
+ #[inline]
+ pub fn create_reaction<M, R>(&self, message_id: M, reaction_type: R)
+ -> Result<()> where M: Into<MessageId>, R: Into<ReactionType> {
+ self.id().create_reaction(message_id, reaction_type)
+ }
+
#[doc(hidden)]
pub fn decode(value: Value) -> Result<Channel> {
let map = into_map(value)?;
@@ -144,7 +186,6 @@ impl Channel {
/// closest functionality is leaving it.
///
/// [`Group`]: struct.Group.html
- #[cfg(feature="methods")]
pub fn delete(&self) -> Result<()> {
match *self {
Channel::Group(ref group) => {
@@ -161,6 +202,122 @@ impl Channel {
Ok(())
}
+ /// Deletes a [`Message`] given its Id.
+ ///
+ /// Refer to [`Message::delete`] for more information.
+ ///
+ /// Requires the [Manage Messages] permission, if the current user is not
+ /// the author of the message.
+ ///
+ /// (in practice, please do not do this)
+ ///
+ /// [`Message`]: struct.Message.html
+ /// [`Message::delete`]: struct.Message.html#method.delete
+ /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
+ #[inline]
+ pub fn delete_message<M: Into<MessageId>>(&self, message_id: M) -> Result<()> {
+ self.id().delete_message(message_id)
+ }
+
+ /// Deletes all messages by Ids from the given vector in the 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.
+ ///
+ /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
+ #[inline]
+ pub fn delete_messages(&self, message_ids: &[MessageId]) -> Result<()> {
+ self.id().delete_messages(message_ids)
+ }
+
+ /// Deletes all permission overrides in the channel from a member
+ /// or role.
+ ///
+ /// **Note**: Requires the [Manage Channel] permission.
+ ///
+ /// [Manage Channel]: permissions/constant.MANAGE_CHANNELS.html
+ #[inline]
+ pub fn delete_permission(&self, permission_type: PermissionOverwriteType) -> Result<()> {
+ self.id().delete_permission(permission_type)
+ }
+
+ /// Deletes the given [`Reaction`] from the channel.
+ ///
+ /// **Note**: Requires the [Manage Messages] permission, _if_ the current
+ /// user did not perform the reaction.
+ ///
+ /// [`Reaction`]: struct.Reaction.html
+ /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
+ #[inline]
+ 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> {
+ self.id().delete_reaction(message_id, user_id, reaction_type)
+ }
+
+ /// Gets a message from the channel.
+ ///
+ /// Requires the [Read Message History] permission.
+ ///
+ /// [Read Message History]: permission/constant.READ_MESSAGE_HISTORY.html
+ #[inline]
+ pub fn get_message<M: Into<MessageId>>(&self, message_id: M) -> Result<Message> {
+ self.id().get_message(message_id)
+ }
+
+ /// Gets messages from the channel.
+ ///
+ /// Requires the [Read Message History] permission.
+ ///
+ /// # Examples
+ ///
+ /// ```rust,ignore
+ /// use serenity::model::ChannelId;
+ ///
+ /// let messages = channel.get_messages(|g| g
+ /// .before(20)
+ /// .after(100)); // Maximum is 100.
+ /// ```
+ ///
+ /// [Read Message History]: permission/constant.READ_MESSAGE_HISTORY.html
+ #[inline]
+ pub fn get_messages<F>(&self, f: F) -> Result<Vec<Message>>
+ where F: FnOnce(GetMessages) -> GetMessages {
+ self.id().get_messages(f)
+ }
+
+ /// 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.
+ ///
+ /// [`Emoji`]: struct.Emoji.html
+ /// [`Message`]: struct.Message.html
+ /// [`User`]: struct.User.html
+ /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
+ #[inline]
+ 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> {
+ self.id().get_reaction_users(message_id, reaction_type, limit, after)
+ }
+
/// Retrieves the Id of the inner [`Group`], [`GuildChannel`], or
/// [`PrivateChannel`].
///
@@ -191,7 +348,6 @@ impl Channel {
/// [`ClientError::InvalidOperationAsBot`]: ../client/enum.ClientError.html#variant.InvalidOperationAsBot
/// [`Message`]: struct.Message.html
/// [`Search`]: ../utils/builder/struct.Search.html
- #[cfg(feature="methods")]
pub fn search<F>(&self, f: F) -> Result<SearchResult>
where F: FnOnce(Search) -> Search {
#[cfg(feature="cache")]
@@ -201,13 +357,18 @@ impl Channel {
}
}
- let id = match *self {
- Channel::Group(ref group) => group.channel_id.0,
- Channel::Guild(ref channel) => channel.id.0,
- Channel::Private(ref channel) => channel.id.0,
- };
+ self.id().search(f)
+ }
- rest::search_channel_messages(id, f(Search::default()).0)
+ /// Unpins a [`Message`] in the channel given by its Id.
+ ///
+ /// Requires the [Manage Messages] permission.
+ ///
+ /// [`Message`]: struct.Message.html
+ /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
+ #[inline]
+ pub fn unpin<M: Into<MessageId>>(&self, message_id: M) -> Result<()> {
+ self.id().unpin(message_id)
}
}
@@ -236,20 +397,509 @@ impl fmt::Display for Channel {
}
}
+impl ChannelId {
+ /// Marks a [`Channel`] as being read up to a certain [`Message`].
+ ///
+ /// Refer to the documentation for [`rest::ack_message`] for more
+ /// information.
+ ///
+ /// [`Channel`]: enum.Channel.html
+ /// [`Message`]: struct.Message.html
+ /// [`rest::ack_message`]: rest/fn.ack_message.html
+ #[inline]
+ pub fn ack<M: Into<MessageId>>(&self, message_id: M) -> Result<()> {
+ rest::ack_message(self.0, message_id.into().0)
+ }
+
+ /// Broadcasts that the current user is typing to a channel for the next 5
+ /// seconds.
+ ///
+ /// After 5 seconds, another request must be made to continue broadcasting
+ /// that the current user is 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.
+ ///
+ /// **Note**: Requires the [Send Messages] permission.
+ ///
+ /// # Examples
+ ///
+ /// ```rust,ignore
+ /// use serenity::model::ChannelId;
+ ///
+ /// let _successful = ChannelId(7).broadcast_typing();
+ /// ```
+ ///
+ /// [Send Messages]: permissions/constant.SEND_MESSAGES.html
+ #[inline]
+ pub fn broadcast_typing(&self) -> Result<()> {
+ rest::broadcast_typing(self.0)
+ }
+
+ /// 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.
+ ///
+ /// [`GuildChannel::create_permission`]: struct.GuildChannel.html#method.create_permission
+ /// [`Member`]: struct.Member.html
+ /// [`PermissionOverwrite`]: struct.PermissionOverWrite.html
+ /// [`Role`]: struct.Role.html
+ /// [Manage Channels]: permissions/constant.MANAGE_CHANNELS.html
+ pub fn create_permission(&self, target: PermissionOverwrite)
+ -> Result<()> {
+ let (id, kind) = match target.kind {
+ PermissionOverwriteType::Member(id) => (id.0, "member"),
+ PermissionOverwriteType::Role(id) => (id.0, "role"),
+ };
+
+ let map = ObjectBuilder::new()
+ .insert("allow", target.allow.bits())
+ .insert("deny", target.deny.bits())
+ .insert("id", id)
+ .insert("type", kind)
+ .build();
+
+ rest::create_permission(self.0, id, map)
+ }
+
+ /// 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.
+ ///
+ /// [`Emoji`]: struct.Emoji.html
+ /// [`Message`]: struct.Message.html
+ /// [`Message::react`]: struct.Message.html#method.react
+ /// [Add Reactions]: permissions/constant.ADD_REACTIONS.html
+ #[inline]
+ pub fn create_reaction<M, R>(&self, message_id: M, reaction_type: R)
+ -> Result<()> where M: Into<MessageId>, R: Into<ReactionType> {
+ rest::create_reaction(self.0, message_id.into().0, reaction_type.into())
+ }
+
+ /// Deletes this channel, returning the channel on a successful deletion.
+ #[inline]
+ pub fn delete(&self) -> Result<Channel> {
+ rest::delete_channel(self.0)
+ }
+
+ /// Deletes a [`Message`] given its Id.
+ ///
+ /// Refer to [`Message::delete`] for more information.
+ ///
+ /// Requires the [Manage Messages] permission, if the current user is not
+ /// the author of the message.
+ ///
+ /// (in practice, please do not do this)
+ ///
+ /// [`Message`]: struct.Message.html
+ /// [`Message::delete`]: struct.Message.html#method.delete
+ /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
+ #[inline]
+ pub fn delete_message<M: Into<MessageId>>(&self, message_id: M) -> Result<()> {
+ rest::delete_message(self.0, message_id.into().0)
+ }
+
+ /// Deletes all messages by Ids from the given vector in the given channel.
+ ///
+ /// Refer to the documentation for [`Channel::delete_messages`] for more
+ /// information.
+ ///
+ /// 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.
+ ///
+ /// [`Channel::delete_messages`]: enum.Channel.html#method.delete_messages
+ /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
+ pub fn delete_messages(&self, message_ids: &[MessageId]) -> Result<()> {
+ let ids = message_ids.into_iter()
+ .map(|message_id| message_id.0)
+ .collect::<Vec<u64>>();
+
+ let map = ObjectBuilder::new().insert("messages", ids).build();
+
+ rest::delete_messages(self.0, map)
+ }
+
+ /// Deletes all permission overrides in the channel from a member or role.
+ ///
+ /// **Note**: Requires the [Manage Channel] permission.
+ ///
+ /// [Manage Channel]: permissions/constant.MANAGE_CHANNELS.html
+ pub fn delete_permission(&self, permission_type: PermissionOverwriteType) -> Result<()> {
+ rest::delete_permission(self.0, match permission_type {
+ PermissionOverwriteType::Member(id) => id.0,
+ PermissionOverwriteType::Role(id) => id.0,
+ })
+ }
+
+ /// Deletes the given [`Reaction`] from the channel.
+ ///
+ /// **Note**: Requires the [Manage Messages] permission, _if_ the current
+ /// user did not perform the reaction.
+ ///
+ /// [`Reaction`]: struct.Reaction.html
+ /// [Manage Messages]: 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> {
+ rest::delete_reaction(self.0,
+ message_id.into().0,
+ user_id.map(|uid| uid.0),
+ reaction_type.into())
+ }
+
+
+ /// 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 channel.
+ ///
+ /// [`Channel`]: enum.Channel.html
+ /// [`ClientError::NoChannelId`]: ../client/enum.ClientError.html#variant.NoChannelId
+ #[inline]
+ pub fn edit<F: FnOnce(EditChannel) -> EditChannel>(&self, f: F) -> Result<GuildChannel> {
+ rest::edit_channel(self.0, f(EditChannel::default()).0.build())
+ }
+
+ /// Edits a [`Message`] in the channel given its Id.
+ ///
+ /// Pass an empty string (`""`) to `text` if you are editing a message with
+ /// an embed or file but no content. Otherwise, `text` must be given.
+ ///
+ /// **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.
+ ///
+ /// [`ClientError::NoChannelId`]: ../client/enum.ClientError.html#variant.NoChannelId
+ /// [`Message`]: 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> {
+ let mut map = ObjectBuilder::new().insert("content", text);
+
+ let embed = f(CreateEmbed::default()).0;
+
+ if embed.len() > 1 {
+ map = map.insert("embed", Value::Object(embed));
+ }
+
+ rest::edit_message(self.0, message_id.into().0, map.build())
+ }
+
+ /// Search the cache for the channel with the Id.
+ #[cfg(feature="cache")]
+ pub fn find(&self) -> Option<Channel> {
+ CACHE.read().unwrap().get_channel(*self).map(|x| x.clone_inner())
+ }
+
+ /// Search the cache for the channel. If it can't be found, the channel is
+ /// requested over REST.
+ pub fn get(&self) -> Result<Channel> {
+ #[cfg(feature="cache")]
+ {
+ if let Some(channel) = CACHE.read().unwrap().get_channel(*self) {
+ return Ok(channel.clone_inner());
+ }
+ }
+
+ rest::get_channel(self.0)
+ }
+
+ /// Gets all of the channel's invites.
+ ///
+ /// Requires the [Manage Channels] permission.
+ /// [Manage Channels]: permissions/constant.MANAGE_CHANNELS.html
+ #[inline]
+ pub fn get_invites(&self) -> Result<Vec<RichInvite>> {
+ rest::get_channel_invites(self.0)
+ }
+
+ /// Gets a message from the channel.
+ ///
+ /// Requires the [Read Message History] permission.
+ ///
+ /// [Read Message History]: permission/constant.READ_MESSAGE_HISTORY.html
+ #[inline]
+ pub fn get_message<M: Into<MessageId>>(&self, message_id: M) -> Result<Message> {
+ rest::get_message(self.0, message_id.into().0)
+ }
+
+ /// Gets messages from the channel.
+ ///
+ /// Refer to [`Channel::get_messages`] for more information.
+ ///
+ /// Requires the [Read Message History] permission.
+ ///
+ /// [`Channel::get_messages`]: enum.Channel.html#method.get_messages
+ /// [Read Message History]: permission/constant.READ_MESSAGE_HISTORY.html
+ pub fn get_messages<F>(&self, f: F) -> Result<Vec<Message>>
+ where F: FnOnce(GetMessages) -> GetMessages {
+ let mut map = f(GetMessages::default()).0;
+ let mut query = format!("?limit={}", map.remove("limit").unwrap_or(50));
+
+ if let Some(after) = map.remove("after") {
+ write!(query, "&after={}", after)?;
+ } else if let Some(around) = map.remove("around") {
+ write!(query, "&around={}", around)?;
+ } else if let Some(before) = map.remove("before") {
+ write!(query, "&before={}", before)?;
+ }
+
+ rest::get_messages(self.0, &query)
+ }
+
+ /// Gets the list of [`User`]s who have reacted to a [`Message`] with a
+ /// certain [`Emoji`].
+ ///
+ /// Refer to [`Channel::get_reaction_users`] for more information.
+ ///
+ /// **Note**: Requires the [Read Message History] permission.
+ ///
+ /// [`Channel::get_reaction_users`]: enum.Channel.html#variant.get_reaction_users
+ /// [`Emoji`]: struct.Emoji.html
+ /// [`Message`]: struct.Message.html
+ /// [`User`]: struct.User.html
+ /// [Read Message History]: 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> {
+ let limit = limit.map_or(50, |x| if x > 100 { 100 } else { x });
+
+ rest::get_reaction_users(self.0,
+ message_id.into().0,
+ reaction_type.into(),
+ limit,
+ after.map(|u| u.into().0))
+ }
+
+ /// Pins a [`Message`] to the channel.
+ #[inline]
+ pub fn pin<M: Into<MessageId>>(&self, message_id: M) -> Result<()> {
+ rest::pin_message(self.0, message_id.into().0)
+ }
+
+ /// Gets the list of [`Message`]s which are pinned to the channel.
+ #[inline]
+ pub fn pins(&self) -> Result<Vec<Message>> {
+ rest::get_pins(self.0)
+ }
+
+ /// Searches the 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].
+ ///
+ /// [`Search`]: ../utils/builder/struct.Search.html
+ #[inline]
+ pub fn search<F: FnOnce(Search) -> Search>(&self, f: F) -> Result<SearchResult> {
+ rest::search_channel_messages(self.0, f(Search::default()).0)
+ }
+
+ /// 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`]: ../client/enum.ClientError.html#variant.MessageTooLong
+ /// [`CreateMessage::content`]: ../utils/builder/struct.CreateMessage.html#method.content
+ /// [`GuildChannel`]: struct.GuildChannel.html
+ /// [Attach Files]: permissions/constant.ATTACH_FILES.html
+ /// [Send Messages]: 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 {
+ let mut map = f(CreateMessage::default()).0;
+
+ if let Some(content) = map.get("content") {
+ if let Value::String(ref content) = *content {
+ if let Some(length_over) = Message::overflow_length(content) {
+ return Err(Error::Client(ClientError::MessageTooLong(length_over)));
+ }
+ }
+ }
+
+ let _ = map.remove("embed");
+
+ rest::send_file(self.0, file, filename, map)
+ }
+
+ /// Sends a message to the channel.
+ ///
+ /// Refer to the documentation for [`CreateMessage`] for more information
+ /// regarding message restrictions and requirements.
+ ///
+ /// Requires the [Send Messages] permission is required.
+ ///
+ /// **Note**: Message contents must be under 2000 unicode code points.
+ ///
+ /// # 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`]: enum.Channel.html
+ /// [`ClientError::MessageTooLong`]: ../client/enum.ClientError.html#variant.MessageTooLong
+ /// [`CreateMessage`]: ../utils/builder/struct.CreateMessage.html
+ /// [Send Messages]: permissions/constant.SEND_MESSAGES.html
+ pub fn send_message<F>(&self, f: F) -> Result<Message>
+ where F: FnOnce(CreateMessage) -> CreateMessage {
+ let map = f(CreateMessage::default()).0;
+
+ if let Some(content) = map.get(&"content".to_owned()) {
+ if let Value::String(ref content) = *content {
+ if let Some(length_over) = Message::overflow_length(content) {
+ return Err(Error::Client(ClientError::MessageTooLong(length_over)));
+ }
+ }
+ }
+
+ rest::send_message(self.0, Value::Object(map))
+ }
+
+ /// Unpins a [`Message`] in the channel given by its Id.
+ ///
+ /// Requires the [Manage Messages] permission.
+ ///
+ /// [`Message`]: struct.Message.html
+ /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
+ #[inline]
+ pub fn unpin<M: Into<MessageId>>(&self, message_id: M) -> Result<()> {
+ rest::unpin_message(self.0, message_id.into().0)
+ }
+
+ /// Retrieves the channel's webhooks.
+ ///
+ /// **Note**: Requires the [Manage Webhooks] permission.
+ ///
+ /// [Manage Webhooks]: permissions/constant.MANAGE_WEBHOOKS.html
+ #[inline]
+ pub fn webhooks(&self) -> Result<Vec<Webhook>> {
+ rest::get_channel_webhooks(self.0)
+ }
+}
+
+impl From<Channel> for ChannelId {
+ /// Gets the Id of a `Channel`.
+ fn from(channel: Channel) -> ChannelId {
+ match channel {
+ Channel::Group(group) => group.channel_id,
+ Channel::Guild(channel) => channel.id,
+ Channel::Private(channel) => channel.id,
+ }
+ }
+}
+
+impl From<PrivateChannel> for ChannelId {
+ /// Gets the Id of a private channel.
+ fn from(private_channel: PrivateChannel) -> ChannelId {
+ private_channel.id
+ }
+}
+
+impl From<GuildChannel> for ChannelId {
+ /// Gets the Id of a guild channel.
+ fn from(public_channel: GuildChannel) -> ChannelId {
+ public_channel.id
+ }
+}
+
+impl fmt::Display for ChannelId {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(&self.0, f)
+ }
+}
+
impl Embed {
/// Creates a fake Embed, giving back a `serde_json` map.
///
/// This should only be useful in conjunction with [`Webhook::execute`].
///
/// [`Webhook::execute`]: struct.Webhook.html
- #[cfg(feature="methods")]
- #[inline(always)]
+ #[inline]
pub fn fake<F>(f: F) -> Value where F: FnOnce(CreateEmbed) -> CreateEmbed {
Value::Object(f(CreateEmbed::default()).0)
}
}
impl Group {
+ /// Marks the group as being read up to a certain [`Message`].
+ ///
+ /// Refer to the documentation for [`rest::ack_message`] for more
+ /// information.
+ ///
+ /// # Errors
+ ///
+ /// If the `cache` is enabled, returns a
+ /// [`ClientError::InvalidOperationAsBot`] if the current user is a bot
+ /// user.
+ ///
+ /// [`ClientError::InvalidOperationAsBot`]: ../client/enum.ClientError.html#variant.InvalidOperationAsUser
+ /// [`Message`]: struct.Message.html
+ /// [`rest::ack_message`]: rest/fn.ack_message.html
+ pub fn ack<M: Into<MessageId>>(&self, message_id: M) -> Result<()> {
+ #[cfg(feature="cache")]
+ {
+ if CACHE.read().unwrap().user.bot {
+ return Err(Error::Client(ClientError::InvalidOperationAsBot));
+ }
+ }
+
+ self.channel_id.ack(message_id)
+ }
+
/// Adds the given user to the group. If the user is already in the group,
/// then nothing is done.
///
@@ -259,7 +909,6 @@ impl Group {
/// user.
///
/// [`rest::add_group_recipient`]: ../client/rest/fn.add_group_recipient.html
- #[cfg(feature="methods")]
pub fn add_recipient<U: Into<UserId>>(&self, user: U) -> Result<()> {
let user = user.into();
@@ -272,43 +921,113 @@ impl Group {
}
/// Broadcasts that the current user is typing in the group.
- #[cfg(feature="methods")]
+ #[inline]
pub fn broadcast_typing(&self) -> Result<()> {
- rest::broadcast_typing(self.channel_id.0)
+ self.channel_id.broadcast_typing()
}
- /// Deletes multiple messages in the group.
+ /// React to a [`Message`] with a custom [`Emoji`] or unicode character.
///
- /// Refer to
- /// [`Context::delete_messages`] for more information.
+ /// [`Message::react`] may be a more suited method of reacting in most
+ /// cases.
///
- /// **Note**: Only 2 to 100 messages may be deleted in a single request.
+ /// Requires the [Add Reactions] permission, _if_ the current user is the
+ /// first user to perform a react with a certain emoji.
///
- /// **Note**: Messages that are older than 2 weeks can't be deleted using this method.
+ /// [`Emoji`]: struct.Emoji.html
+ /// [`Message`]: struct.Message.html
+ /// [`Message::react`]: struct.Message.html#method.react
+ /// [Add Reactions]: permissions/constant.ADD_REACTIONS.html
+ #[inline]
+ pub fn create_reaction<M, R>(&self, message_id: M, reaction_type: R)
+ -> Result<()> where M: Into<MessageId>, R: Into<ReactionType> {
+ self.channel_id.create_reaction(message_id, reaction_type)
+ }
+
+ /// Deletes all messages by Ids from the given vector in the channel.
///
- /// # Errors
+ /// Refer to [`Channel::delete_messages`] for more information.
///
- /// Returns a
- /// [`ClientError::DeleteMessageDaysAmount`] if the number of messages to
- /// delete is not within the valid range.
+ /// Requires the [Manage Messages] permission.
///
- /// [`ClientError::DeleteMessageDaysAmount`]: ../client/enum.ClientError.html#variant.DeleteMessageDaysAmount
- /// [`Context::delete_messages`]: ../client/struct.Context.html#delete_messages
- #[cfg(feature="methods")]
+ /// **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.
+ ///
+ /// [`Channel::delete_messages`]: enum.Channel.html#method.delete_messages
+ /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
+ #[inline]
pub fn delete_messages(&self, message_ids: &[MessageId]) -> Result<()> {
- if message_ids.len() < 2 || message_ids.len() > 100 {
- return Err(Error::Client(ClientError::BulkDeleteAmount));
- }
+ self.channel_id.delete_messages(message_ids)
+ }
- let ids: Vec<u64> = message_ids.into_iter()
- .map(|message_id| message_id.0)
- .collect();
+ /// Deletes all permission overrides in the channel from a member
+ /// or role.
+ ///
+ /// **Note**: Requires the [Manage Channel] permission.
+ ///
+ /// [Manage Channel]: permissions/constant.MANAGE_CHANNELS.html
+ #[inline]
+ pub fn delete_permission(&self, permission_type: PermissionOverwriteType) -> Result<()> {
+ self.channel_id.delete_permission(permission_type)
+ }
- let map = ObjectBuilder::new()
- .insert("messages", ids)
- .build();
+ /// Deletes the given [`Reaction`] from the channel.
+ ///
+ /// **Note**: Requires the [Manage Messages] permission, _if_ the current
+ /// user did not perform the reaction.
+ ///
+ /// [`Reaction`]: struct.Reaction.html
+ /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
+ #[inline]
+ 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> {
+ self.channel_id.delete_reaction(message_id, user_id, reaction_type)
+ }
- rest::delete_messages(self.channel_id.0, map)
+ /// Gets a message from the channel.
+ ///
+ /// Requires the [Read Message History] permission.
+ ///
+ /// [Read Message History]: permission/constant.READ_MESSAGE_HISTORY.html
+ #[inline]
+ pub fn get_message<M: Into<MessageId>>(&self, message_id: M) -> Result<Message> {
+ self.channel_id.get_message(message_id)
+ }
+
+ /// Gets messages from the channel.
+ ///
+ /// Requires the [Read Message History] permission.
+ ///
+ /// [Read Message History]: permission/constant.READ_MESSAGE_HISTORY.html
+ #[inline]
+ pub fn get_messages<F>(&self, f: F) -> Result<Vec<Message>>
+ where F: FnOnce(GetMessages) -> GetMessages {
+ self.channel_id.get_messages(f)
+ }
+
+ /// Gets the list of [`User`]s who have reacted to a [`Message`] with a
+ /// certain [`Emoji`].
+ ///
+ /// Refer to [`Channel::get_reaction_users`] for more information.
+ ///
+ /// **Note**: Requires the [Read Message History] permission.
+ ///
+ /// [`Channel::get_reaction_users`]: enum.Channel.html#variant.get_reaction_users
+ /// [`Emoji`]: struct.Emoji.html
+ /// [`Message`]: struct.Message.html
+ /// [`User`]: struct.User.html
+ /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
+ #[inline]
+ 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> {
+ self.channel_id.get_reaction_users(message_id, reaction_type, limit, after)
}
/// Returns the formatted URI of the group's icon if one exists.
@@ -318,7 +1037,7 @@ impl Group {
}
/// Leaves the group.
- #[cfg(feature="methods")]
+ #[inline]
pub fn leave(&self) -> Result<Group> {
rest::leave_group(self.channel_id.0)
}
@@ -347,16 +1066,15 @@ impl Group {
}
/// Retrieves the list of messages that have been pinned in the group.
- #[cfg(feature="methods")]
+ #[inline]
pub fn pins(&self) -> Result<Vec<Message>> {
- rest::get_pins(self.channel_id.0)
+ self.channel_id.pins()
}
/// Removes a recipient from the group. If the recipient is already not in
/// the group, then nothing is done.
///
/// **Note**: This is only available to the group owner.
- #[cfg(feature="methods")]
pub fn remove_recipient<U: Into<UserId>>(&self, user: U) -> Result<()> {
let user = user.into();
@@ -384,10 +1102,10 @@ impl Group {
/// [`ClientError::InvalidOperationAsBot`]: ../client/enum.ClientError.html#variant.InvalidOperationAsBot
/// [`Message`]: struct.Message.html
/// [`Search`]: ../utils/builder/struct.Search.html
- #[cfg(feature="methods")]
+ #[inline]
pub fn search<F>(&self, f: F) -> Result<SearchResult>
where F: FnOnce(Search) -> Search {
- rest::search_channel_messages(self.channel_id.0, f(Search::default()).0)
+ self.channel_id.search(f)
}
/// Sends a message to the group with the given content.
@@ -397,19 +1115,50 @@ impl Group {
/// **Note**: Requires the [Send Messages] permission.
///
/// [Send Messages]: permissions/constant.SEND_MESSAGES.html
- #[cfg(feature="methods")]
+ #[inline]
pub fn send_message(&self, content: &str) -> Result<Message> {
- let map = ObjectBuilder::new()
- .insert("content", content)
- .insert("nonce", "")
- .insert("tts", false)
- .build();
+ self.channel_id.send_message(|m| m.content(content))
+ }
- rest::send_message(self.channel_id.0, map)
+ /// Unpins a [`Message`] in the channel given by its Id.
+ ///
+ /// Requires the [Manage Messages] permission.
+ ///
+ /// [`Message`]: struct.Message.html
+ /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
+ #[inline]
+ pub fn unpin<M: Into<MessageId>>(&self, message_id: M) -> Result<()> {
+ self.channel_id.unpin(message_id.into().0)
}
}
impl Message {
+ /// Marks the [`Channel`] as being read up to the message.
+ ///
+ /// Refer to the documentation for [`rest::ack_message`] for more
+ /// information.
+ ///
+ /// # Errors
+ ///
+ /// If the `cache` is enabled, returns a
+ /// [`ClientError::InvalidOperationAsBot`] if the current user is a bot
+ /// user.
+ ///
+ /// [`Channel`]: enum.Channel.html
+ /// [`ClientError::InvalidOperationAsBot`]: ../client/enum.ClientError.html#variant.InvalidOperationAsUser
+ /// [`Message`]: struct.Message.html
+ /// [`rest::ack_message`]: rest/fn.ack_message.html
+ pub fn ack<M: Into<MessageId>>(&self) -> Result<()> {
+ #[cfg(feature="cache")]
+ {
+ if CACHE.read().unwrap().user.bot {
+ return Err(Error::Client(ClientError::InvalidOperationAsBot));
+ }
+ }
+
+ self.channel_id.ack(self.id)
+ }
+
/// Deletes the message.
///
/// **Note**: The logged in user must either be the author of the message or
@@ -424,7 +1173,6 @@ impl Message {
/// [`ClientError::InvalidPermissions`]: ../client/enum.ClientError.html#variant.InvalidPermissions
/// [`ClientError::InvalidUser`]: ../client/enum.ClientError.html#variant.InvalidUser
/// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
- #[cfg(feature="methods")]
pub fn delete(&self) -> Result<()> {
#[cfg(feature="cache")]
{
@@ -437,7 +1185,7 @@ impl Message {
}
}
- rest::delete_message(self.channel_id.0, self.id.0)
+ self.channel_id.delete_message(self.id)
}
/// Deletes all of the [`Reaction`]s associated with the message.
@@ -453,7 +1201,6 @@ impl Message {
/// [`ClientError::InvalidPermissions`]: ../client/enum.ClientError.html#variant.InvalidPermissions
/// [`Reaction`]: struct.Reaction.html
/// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
- #[cfg(feature="methods")]
pub fn delete_reactions(&self) -> Result<()> {
#[cfg(feature="cache")]
{
@@ -490,8 +1237,7 @@ impl Message {
/// over the limit.
///
/// [`ClientError::InvalidUser`]: ../client/enum.ClientError.html#variant.InvalidUser
- /// [`ClientError::MessageTooLong`]: enum.ClientError.html#variant.MessageTooLong
- #[cfg(feature="methods")]
+ /// [`ClientError::MessageTooLong`]: ../client/enum.ClientError.html#variant.MessageTooLong
pub fn edit<F>(&mut self, new_content: &str, embed: F) -> Result<()>
where F: FnOnce(CreateEmbed) -> CreateEmbed {
if let Some(length_over) = Message::overflow_length(new_content) {
@@ -525,7 +1271,7 @@ impl Message {
/// Returns message content, but with user and role mentions replaced with
/// names and everyone/here mentions cancelled.
- #[cfg(all(feature="cache", feature="methods"))]
+ #[cfg(feature="cache")]
pub fn content_safe(&self) -> String {
let mut result = self.content.clone();
@@ -550,12 +1296,34 @@ impl Message {
.replace("@here", "@\u{200B}here")
}
+ /// 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.
+ ///
+ /// [`Emoji`]: struct.Emoji.html
+ /// [`Message`]: struct.Message.html
+ /// [`User`]: struct.User.html
+ /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
+ #[inline]
+ pub fn get_reaction_users<R, U>(&self, reaction_type: R, limit: Option<u8>, after: Option<U>)
+ -> Result<Vec<User>> where R: Into<ReactionType>, U: Into<UserId> {
+ self.id.get_reaction_users(self.channel_id, reaction_type, limit, after)
+ }
+
/// Retrieves the Id of the guild that the message was sent in, if sent in
/// one.
///
/// Returns `None` if the channel data or guild data does not exist in the
/// cache.
- #[cfg(all(feature="cache", feature="methods"))]
+ #[cfg(feature="cache")]
pub fn guild_id(&self) -> Option<GuildId> {
match CACHE.read().unwrap().get_channel(self.channel_id) {
Some(ChannelRef::Guild(channel)) => Some(channel.guild_id),
@@ -564,7 +1332,7 @@ impl Message {
}
/// True if message was sent using direct messages.
- #[cfg(all(feature="cache", feature="methods"))]
+ #[cfg(feature="cache")]
pub fn is_private(&self) -> bool {
match CACHE.read().unwrap().get_channel(self.channel_id) {
Some(ChannelRef::Group(_)) | Some(ChannelRef::Private(_)) => true,
@@ -603,7 +1371,6 @@ impl Message {
///
/// [`ClientError::InvalidPermissions`]: ../client/enum.ClientError.html#variant.InvalidPermissions
/// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
- #[cfg(feature="methods")]
pub fn pin(&self) -> Result<()> {
#[cfg(feature="cache")]
{
@@ -614,7 +1381,7 @@ impl Message {
}
}
- rest::pin_message(self.channel_id.0, self.id.0)
+ self.channel_id.pin(self.id.0)
}
/// React to the message with a custom [`Emoji`] or unicode character.
@@ -631,7 +1398,6 @@ impl Message {
/// [`Emoji`]: struct.Emoji.html
/// [Add Reactions]: permissions/constant.ADD_REACTIONS.html
/// [permissions]: permissions
- #[cfg(feature="methods")]
pub fn react<R: Into<ReactionType>>(&self, reaction_type: R) -> Result<()> {
#[cfg(feature="cache")]
{
@@ -667,9 +1433,8 @@ impl Message {
/// over the limit.
///
/// [`ClientError::InvalidPermissions`]: ../client/enum.ClientError.html#variant.InvalidPermissions
- /// [`ClientError::MessageTooLong`]: enum.ClientError.html#variant.MessageTooLong
+ /// [`ClientError::MessageTooLong`]: ../client/enum.ClientError.html#variant.MessageTooLong
/// [Send Messages]: permissions/constant.SEND_MESSAGES.html
- #[cfg(feature="methods")]
pub fn reply(&self, content: &str) -> Result<Message> {
if let Some(length_over) = Message::overflow_length(content) {
return Err(Error::Client(ClientError::MessageTooLong(length_over)));
@@ -709,7 +1474,6 @@ impl Message {
///
/// [`ClientError::InvalidPermissions`]: ../client/enum.ClientError.html#variant.InvalidPermissions
/// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
- #[cfg(feature="methods")]
pub fn unpin(&self) -> Result<()> {
#[cfg(feature="cache")]
{
@@ -724,6 +1488,46 @@ impl Message {
}
}
+impl MessageId {
+ /// 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.
+ ///
+ /// [`Emoji`]: struct.Emoji.html
+ /// [`Message`]: struct.Message.html
+ /// [`User`]: struct.User.html
+ /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
+ pub fn get_reaction_users<C, R, U>(&self,
+ channel_id: C,
+ reaction_type: R,
+ limit: Option<u8>,
+ after: Option<U>)
+ -> Result<Vec<User>> where C: Into<ChannelId>, R: Into<ReactionType>, U: Into<UserId> {
+ let limit = limit.map_or(50, |x| if x > 100 { 100 } else { x });
+
+ rest::get_reaction_users(channel_id.into().0,
+ self.0,
+ reaction_type.into(),
+ limit,
+ after.map(|u| u.into().0))
+ }
+}
+
+impl From<Message> for MessageId {
+ /// Gets the Id of a `Message`.
+ fn from(message: Message) -> MessageId {
+ message.id
+ }
+}
+
impl PermissionOverwrite {
#[doc(hidden)]
pub fn decode(value: Value) -> Result<PermissionOverwrite> {
@@ -745,12 +1549,53 @@ impl PermissionOverwrite {
}
impl PrivateChannel {
+ /// Marks the channel as being read up to a certain [`Message`].
+ ///
+ /// Refer to the documentation for [`rest::ack_message`] for more
+ /// information.
+ ///
+ /// # Errors
+ ///
+ /// If the `cache` is enabled, returns a
+ /// [`ClientError::InvalidOperationAsBot`] if the current user is a bot
+ /// user.
+ ///
+ /// [`ClientError::InvalidOperationAsBot`]: ../client/enum.ClientError.html#variant.InvalidOperationAsUser
+ /// [`Message`]: struct.Message.html
+ /// [`rest::ack_message`]: rest/fn.ack_message.html
+ pub fn ack<M: Into<MessageId>>(&self, message_id: M) -> Result<()> {
+ #[cfg(feature="cache")]
+ {
+ if CACHE.read().unwrap().user.bot {
+ return Err(Error::Client(ClientError::InvalidOperationAsBot));
+ }
+ }
+
+ rest::ack_message(self.id.0, message_id.into().0)
+ }
+
/// Broadcasts that the current user is typing to the recipient.
- #[cfg(feature="methods")]
pub fn broadcast_typing(&self) -> Result<()> {
rest::broadcast_typing(self.id.0)
}
+ /// 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.
+ ///
+ /// [`Emoji`]: struct.Emoji.html
+ /// [`Message`]: struct.Message.html
+ /// [`Message::react`]: struct.Message.html#method.react
+ /// [Add Reactions]: 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> {
+ self.id.create_reaction(message_id, reaction_type)
+ }
+
#[doc(hidden)]
pub fn decode(value: Value) -> Result<PrivateChannel> {
let mut map = into_map(value)?;
@@ -769,50 +1614,111 @@ impl PrivateChannel {
/// Deletes the channel. This does not delete the contents of the channel,
/// and is equivalent to closing a private channel on the client, which can
/// be re-opened.
- #[cfg(feature="methods")]
+ #[inline]
pub fn delete(&self) -> Result<Channel> {
- rest::delete_channel(self.id.0)
+ self.id.delete()
}
- /// Deletes the given message Ids from the private channel.
+ /// Deletes all messages by Ids from the given vector in the channel.
+ ///
+ /// Refer to [`Channel::delete_messages`] for more information.
///
- /// **Note** This method is only available to bot users and they can't
- /// delete their recipient's messages.
+ /// 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
+ /// [`Channel::delete_messages`]: enum.Channel.html#method.delete_messages
+ /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
+ #[inline]
+ pub fn delete_messages(&self, message_ids: &[MessageId]) -> Result<()> {
+ self.id.delete_messages(message_ids)
+ }
+
+ /// Deletes all permission overrides in the channel from a member
+ /// or role.
///
- /// If the `cache` is enabled, then returns a
- /// [`ClientError::InvalidUser`] if the current user is not a bot user.
+ /// **Note**: Requires the [Manage Channel] permission.
///
- /// [`ClientError::InvalidUser`]: ../client/enum.ClientError.html#variant.InvalidOperationAsUser
- #[cfg(feature="methods")]
- pub fn delete_messages(&self, message_ids: &[MessageId]) -> Result<()> {
- #[cfg(feature="cache")]
- {
- if !CACHE.read().unwrap().user.bot {
- return Err(Error::Client(ClientError::InvalidOperationAsUser));
- }
- }
+ /// [Manage Channel]: permissions/constant.MANAGE_CHANNELS.html
+ #[inline]
+ pub fn delete_permission(&self, permission_type: PermissionOverwriteType) -> Result<()> {
+ self.id.delete_permission(permission_type)
+ }
- let ids: Vec<u64> = message_ids.into_iter()
- .map(|message_id| message_id.0)
- .collect();
+ /// Deletes the given [`Reaction`] from the channel.
+ ///
+ /// **Note**: Requires the [Manage Messages] permission, _if_ the current
+ /// user did not perform the reaction.
+ ///
+ /// [`Reaction`]: struct.Reaction.html
+ /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
+ #[inline]
+ 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> {
+ self.id.delete_reaction(message_id, user_id, reaction_type)
+ }
- let map = ObjectBuilder::new()
- .insert("messages", ids)
- .build();
+ /// Gets a message from the channel.
+ ///
+ /// Requires the [Read Message History] permission.
+ ///
+ /// [Read Message History]: permission/constant.READ_MESSAGE_HISTORY.html
+ #[inline]
+ pub fn get_message<M: Into<MessageId>>(&self, message_id: M) -> Result<Message> {
+ self.id.get_message(message_id)
+ }
+
+ /// Gets messages from the channel.
+ ///
+ /// Refer to [`Channel::get_messages`] for more information.
+ ///
+ /// Requires the [Read Message History] permission.
+ ///
+ /// [`Channel::get_messages`]: enum.Channel.html#method.get_messages
+ /// [Read Message History]: permission/constant.READ_MESSAGE_HISTORY.html
+ #[inline]
+ pub fn get_messages<F>(&self, f: F) -> Result<Vec<Message>>
+ where F: FnOnce(GetMessages) -> GetMessages {
+ self.id.get_messages(f)
+ }
+
+ /// Gets the list of [`User`]s who have reacted to a [`Message`] with a
+ /// certain [`Emoji`].
+ ///
+ /// Refer to [`Channel::get_reaction_users`] for more information.
+ ///
+ /// **Note**: Requires the [Read Message History] permission.
+ ///
+ /// [`Channel::get_reaction_users`]: enum.Channel.html#variant.get_reaction_users
+ /// [`Emoji`]: struct.Emoji.html
+ /// [`Message`]: struct.Message.html
+ /// [`User`]: struct.User.html
+ /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
+ #[inline]
+ 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> {
+ self.id.get_reaction_users(message_id, reaction_type, limit, after)
+ }
- rest::delete_messages(self.id.0, map)
+ /// Pins a [`Message`] to the channel.
+ #[inline]
+ pub fn pin<M: Into<MessageId>>(&self, message_id: M) -> Result<()> {
+ self.id.pin(message_id)
}
/// Retrieves the list of messages that have been pinned in the private
/// channel.
- #[cfg(feature="methods")]
+ #[inline]
pub fn pins(&self) -> Result<Vec<Message>> {
- rest::get_pins(self.id.0)
+ self.id.pins()
}
/// Performs a search request to the API for the channel's [`Message`]s.
@@ -830,7 +1736,6 @@ impl PrivateChannel {
/// [`ClientError::InvalidOperationAsBot`]: ../client/enum.ClientError.html#variant.InvalidOperationAsBot
/// [`Message`]: struct.Message.html
/// [`Search`]: ../utils/builder/struct.Search.html
- #[cfg(feature="methods")]
pub fn search<F>(&self, f: F) -> Result<SearchResult>
where F: FnOnce(Search) -> Search {
#[cfg(feature="cache")]
@@ -840,7 +1745,7 @@ impl PrivateChannel {
}
}
- rest::search_channel_messages(self.id.0, f(Search::default()).0)
+ self.id.search(f)
}
/// Sends a message to the channel with the given content.
@@ -854,7 +1759,6 @@ impl PrivateChannel {
/// over the limit.
///
/// [`ClientError::MessageTooLong`]: ../client/enum.ClientError.html#variant.MessageTooLong
- #[cfg(feature="methods")]
pub fn send_message(&self, content: &str) -> Result<Message> {
if let Some(length_over) = Message::overflow_length(content) {
return Err(Error::Client(ClientError::MessageTooLong(length_over)));
@@ -868,6 +1772,17 @@ impl PrivateChannel {
rest::send_message(self.id.0, map)
}
+
+ /// Unpins a [`Message`] in the channel given by its Id.
+ ///
+ /// Requires the [Manage Messages] permission.
+ ///
+ /// [`Message`]: struct.Message.html
+ /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
+ #[inline]
+ pub fn unpin<M: Into<MessageId>>(&self, message_id: M) -> Result<()> {
+ self.id.unpin(message_id.into().0)
+ }
}
impl fmt::Display for PrivateChannel {
@@ -878,6 +1793,31 @@ impl fmt::Display for PrivateChannel {
}
impl GuildChannel {
+ /// Marks the channel as being read up to a certain [`Message`].
+ ///
+ /// Refer to the documentation for [`rest::ack_message`] for more
+ /// information.
+ ///
+ /// # Errors
+ ///
+ /// If the `cache` is enabled, returns a
+ /// [`ClientError::InvalidOperationAsBot`] if the current user is a bot
+ /// user.
+ ///
+ /// [`ClientError::InvalidOperationAsBot`]: ../client/enum.ClientError.html#variant.InvalidOperationAsUser
+ /// [`Message`]: struct.Message.html
+ /// [`rest::ack_message`]: rest/fn.ack_message.html
+ pub fn ack<M: Into<MessageId>>(&self, message_id: M) -> Result<()> {
+ #[cfg(feature="cache")]
+ {
+ if CACHE.read().unwrap().user.bot {
+ return Err(Error::Client(ClientError::InvalidOperationAsBot));
+ }
+ }
+
+ rest::ack_message(self.id.0, message_id.into().0)
+ }
+
/// Broadcasts to the channel that the current user is typing.
///
/// For bots, this is a good indicator for long-running commands.
@@ -892,7 +1832,6 @@ impl GuildChannel {
///
/// [`ClientError::InvalidPermissions`]: ../client/enum.ClientError.html#variant.InvalidPermissions
/// [Send Messages]: permissions/constants.SEND_MESSAGES.html
- #[cfg(feature="methods")]
pub fn broadcast_typing(&self) -> Result<()> {
rest::broadcast_typing(self.id.0)
}
@@ -907,7 +1846,6 @@ impl GuildChannel {
/// let invite = channel.create_invite(|i| i
/// .max_uses(5));
/// ```
- #[cfg(feature="methods")]
pub fn create_invite<F>(&self, f: F) -> Result<RichInvite>
where F: FnOnce(CreateInvite) -> CreateInvite {
#[cfg(feature="cache")]
@@ -924,6 +1862,78 @@ impl GuildChannel {
rest::create_invite(self.id.0, map)
}
+ /// Creates a [permission overwrite][`PermissionOverwrite`] for either a
+ /// single [`Member`] or [`Role`] within a [`Channel`].
+ ///
+ /// Refer to the documentation for [`PermissionOverwrite`]s for more
+ /// information.
+ ///
+ /// Requires the [Manage Channels] permission.
+ ///
+ /// # Examples
+ ///
+ /// Creating a permission overwrite for a member by specifying the
+ /// [`PermissionOverwrite::Member`] variant, allowing it the [Send Messages]
+ /// permission, but denying the [Send TTS Messages] and [Attach Files]
+ /// permissions:
+ ///
+ /// ```rust,ignore
+ /// use serenity::model::{ChannelId, PermissionOverwrite, permissions};
+ ///
+ /// // assuming you are in a context
+ ///
+ /// let channel_id = 7;
+ /// let user_id = 8;
+ ///
+ /// let allow = permissions::SEND_MESSAGES;
+ /// let deny = permissions::SEND_TTS_MESSAGES | permissions::ATTACH_FILES;
+ /// let overwrite = PermissionOverwrite {
+ /// allow: allow,
+ /// deny: deny,
+ /// kind: PermissionOverwriteType::Member(user_id),
+ /// };
+ ///
+ /// let _result = context.create_permission(channel_id, overwrite);
+ /// ```
+ ///
+ /// Creating a permission overwrite for a role by specifying the
+ /// [`PermissionOverwrite::Role`] variant, allowing it the [Manage Webhooks]
+ /// permission, but denying the [Send TTS Messages] and [Attach Files]
+ /// permissions:
+ ///
+ /// ```rust,ignore
+ /// use serenity::model::{ChannelId, PermissionOverwrite, permissions};
+ ///
+ /// // assuming you are in a context
+ ///
+ /// let channel_id = 7;
+ /// let user_id = 8;
+ ///
+ /// let allow = permissions::SEND_MESSAGES;
+ /// let deny = permissions::SEND_TTS_MESSAGES | permissions::ATTACH_FILES;
+ /// let overwrite = PermissionOverwrite {
+ /// allow: allow,
+ /// deny: deny,
+ /// kind: PermissionOverwriteType::Member(user_id),
+ /// };
+ ///
+ /// let _result = context.create_permission(channel_id, overwrite);
+ /// ```
+ ///
+ /// [`Channel`]: enum.Channel.html
+ /// [`Member`]: struct.Member.html
+ /// [`PermissionOverwrite`]: struct.PermissionOverWrite.html
+ /// [`PermissionOverwrite::Member`]: struct.PermissionOverwrite.html#variant.Member
+ /// [`Role`]: struct.Role.html
+ /// [Attach Files]: permissions/constant.ATTACH_FILES.html
+ /// [Manage Channels]: permissions/constant.MANAGE_CHANNELS.html
+ /// [Manage Webhooks]: permissions/constant.MANAGE_WEBHOOKS.html
+ /// [Send TTS Messages]: permissions/constant.SEND_TTS_MESSAGES.html
+ #[inline]
+ pub fn create_permission(&self, target: PermissionOverwrite) -> Result<()> {
+ self.id.create_permission(target)
+ }
+
#[doc(hidden)]
pub fn decode(value: Value) -> Result<GuildChannel> {
let mut map = into_map(value)?;
@@ -953,7 +1963,6 @@ impl GuildChannel {
}
/// Deletes this channel, returning the channel on a successful deletion.
- #[cfg(feature="methods")]
pub fn delete(&self) -> Result<Channel> {
#[cfg(feature="cache")]
{
@@ -964,7 +1973,50 @@ impl GuildChannel {
}
}
- rest::delete_channel(self.id.0)
+ self.id.delete()
+ }
+
+ /// Deletes all messages by Ids from the given vector in the channel.
+ ///
+ /// Refer to [`Channel::delete_messages`] for more information.
+ ///
+ /// 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.
+ ///
+ /// [`Channel::delete_messages`]: enum.Channel.html#method.delete_messages
+ /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
+ #[inline]
+ pub fn delete_messages(&self, message_ids: &[MessageId]) -> Result<()> {
+ self.id.delete_messages(message_ids)
+ }
+
+ /// Deletes all permission overrides in the channel from a member
+ /// or role.
+ ///
+ /// **Note**: Requires the [Manage Channel] permission.
+ ///
+ /// [Manage Channel]: permissions/constant.MANAGE_CHANNELS.html
+ #[inline]
+ pub fn delete_permission(&self, permission_type: PermissionOverwriteType) -> Result<()> {
+ self.id.delete_permission(permission_type)
+ }
+
+ /// Deletes the given [`Reaction`] from the channel.
+ ///
+ /// **Note**: Requires the [Manage Messages] permission, _if_ the current
+ /// user did not perform the reaction.
+ ///
+ /// [`Reaction`]: struct.Reaction.html
+ /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
+ #[inline]
+ 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> {
+ self.id.delete_reaction(message_id, user_id, reaction_type)
}
/// Modifies a channel's settings, such as its position or name.
@@ -980,7 +2032,6 @@ impl GuildChannel {
/// .name("test")
/// .bitrate(86400));
/// ```
- #[cfg(feature="methods")]
pub fn edit<F>(&mut self, f: F) -> Result<()>
where F: FnOnce(EditChannel) -> EditChannel {
@@ -1010,19 +2061,79 @@ impl GuildChannel {
}
}
+ /// Gets all of the channel's invites.
+ ///
+ /// Requires the [Manage Channels] permission.
+ /// [Manage Channels]: permissions/constant.MANAGE_CHANNELS.html
+ #[inline]
+ pub fn get_invites(&self) -> Result<Vec<RichInvite>> {
+ self.id.get_invites()
+ }
+
+ /// Gets a message from the channel.
+ ///
+ /// Requires the [Read Message History] permission.
+ ///
+ /// [Read Message History]: permission/constant.READ_MESSAGE_HISTORY.html
+ #[inline]
+ pub fn get_message<M: Into<MessageId>>(&self, message_id: M) -> Result<Message> {
+ self.id.get_message(message_id)
+ }
+
+ /// Gets messages from the channel.
+ ///
+ /// Refer to [`Channel::get_messages`] for more information.
+ ///
+ /// Requires the [Read Message History] permission.
+ ///
+ /// [`Channel::get_messages`]: enum.Channel.html#method.get_messages
+ /// [Read Message History]: permission/constant.READ_MESSAGE_HISTORY.html
+ #[inline]
+ pub fn get_messages<F>(&self, f: F) -> Result<Vec<Message>>
+ where F: FnOnce(GetMessages) -> GetMessages {
+ self.id.get_messages(f)
+ }
+
+ /// Gets the list of [`User`]s who have reacted to a [`Message`] with a
+ /// certain [`Emoji`].
+ ///
+ /// Refer to [`Channel::get_reaction_users`] for more information.
+ ///
+ /// **Note**: Requires the [Read Message History] permission.
+ ///
+ /// [`Channel::get_reaction_users`]: enum.Channel.html#variant.get_reaction_users
+ /// [`Emoji`]: struct.Emoji.html
+ /// [`Message`]: struct.Message.html
+ /// [`User`]: struct.User.html
+ /// [Read Message History]: 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> {
+ self.id.get_reaction_users(message_id, reaction_type, limit, after)
+ }
+
/// Attempts to find this channel's guild in the Cache.
///
/// **Note**: Right now this performs a clone of the guild. This will be
/// optimized in the future.
- #[cfg(all(feature="cache", feature="methods"))]
+ #[cfg(feature="cache")]
pub fn guild(&self) -> Option<Guild> {
CACHE.read().unwrap().get_guild(self.guild_id).cloned()
}
+ /// Pins a [`Message`] to the channel.
+ #[inline]
+ pub fn pin<M: Into<MessageId>>(&self, message_id: M) -> Result<()> {
+ self.id.pin(message_id)
+ }
+
/// Gets all channel's pins.
- #[cfg(feature="methods")]
+ #[inline]
pub fn pins(&self) -> Result<Vec<Message>> {
- rest::get_pins(self.id.0)
+ self.id.pins()
}
/// Performs a search request for the channel's [`Message`]s.
@@ -1040,7 +2151,6 @@ impl GuildChannel {
/// [`ClientError::InvalidOperationAsBot`]: ../client/enum.ClientError.html#variant.InvalidOperationAsBot
/// [`Message`]: struct.Message.html
/// [`Search`]: ../utils/builder/struct.Search.html
- #[cfg(feature="methods")]
pub fn search<F>(&self, f: F) -> Result<SearchResult>
where F: FnOnce(Search) -> Search {
#[cfg(feature="cache")]
@@ -1072,7 +2182,6 @@ impl GuildChannel {
/// [`ClientError::MessageTooLong`]: ../client/enum.ClientError.html#variant.MessageTooLong
/// [`Message`]: struct.Message.html
/// [Send Messages]: permissions/constant.SEND_MESSAGES.html
- #[cfg(feature="methods")]
pub fn send_message(&self, content: &str) -> Result<Message> {
if let Some(length_over) = Message::overflow_length(content) {
return Err(Error::Client(ClientError::MessageTooLong(length_over)));
@@ -1096,12 +2205,22 @@ impl GuildChannel {
rest::send_message(self.id.0, map)
}
+ /// Unpins a [`Message`] in the channel given by its Id.
+ ///
+ /// Requires the [Manage Messages] permission.
+ ///
+ /// [`Message`]: struct.Message.html
+ /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
+ #[inline]
+ pub fn unpin<M: Into<MessageId>>(&self, message_id: M) -> Result<()> {
+ self.id.unpin(message_id.into().0)
+ }
+
/// Retrieves the channel's webhooks.
///
/// **Note**: Requires the [Manage Webhooks] permission.
///
/// [Manage Webhooks]: permissions/constant.MANAGE_WEBHOOKS.html
- #[cfg(feature="methods")]
#[inline]
pub fn webhooks(&self) -> Result<Vec<Webhook>> {
rest::get_channel_webhooks(self.id.0)
@@ -1131,7 +2250,6 @@ impl Reaction {
/// [`ClientError::InvalidPermissions`]: ../client/enum.ClientError.html#variant.InvalidPermissions
/// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
/// [permissions]: permissions
- #[cfg(feature="methods")]
pub fn delete(&self) -> Result<()> {
let user_id = feature_cache! {{
let user = if self.user_id == CACHE.read().unwrap().user.id {
@@ -1188,7 +2306,6 @@ impl Reaction {
/// [`User`]: struct.User.html
/// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
/// [permissions]: permissions
- #[cfg(feature="methods")]
pub fn users<R, U>(&self,
reaction_type: R,
limit: Option<u8>,