diff options
Diffstat (limited to 'src/model/channel/channel_id.rs')
| -rw-r--r-- | src/model/channel/channel_id.rs | 511 |
1 files changed, 511 insertions, 0 deletions
diff --git a/src/model/channel/channel_id.rs b/src/model/channel/channel_id.rs new file mode 100644 index 0000000..2d09367 --- /dev/null +++ b/src/model/channel/channel_id.rs @@ -0,0 +1,511 @@ +use serde_json::builder::ObjectBuilder; +use std::fmt::{Display, Formatter, Result as FmtResult, Write as FmtWrite}; +use std::io::Read; +use ::client::{CACHE, rest}; +use ::model::*; +use ::utils::builder::{CreateMessage, EditChannel, GetMessages, Search}; + +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. + /// + /// [`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 + /// // assuming a `channel_id` has been bound + /// + /// channel_id.edit(|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 + /// [Manage Channel]: permissions/constant.MANAGE_CHANNELS.html + #[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. + /// + /// Message editing preserves all unchanged message data. + /// + /// Refer to the documentation for [`CreateMessage`] for more information + /// regarding message restrictions and requirements. + /// + /// **Note**: Requires that the current user be the author of the message. + /// + /// # Errors + /// + /// Returns a [`ClientError::MessageTooLong`] if the content of the message + /// is over the [`the limit`], containing the number of unicode code points + /// over the limit. + /// + /// [`ClientError::MessageTooLong`]: ../client/enum.ClientError.html#variant.MessageTooLong + /// [`CreateMessage`]: ../utils/builder/struct.CreateMessage.html + /// [`Message`]: struct.Message.html + /// [`the limit`]: ../utils/builder/struct.CreateMessage.html#method.content + pub fn edit_message<F, M>(&self, message_id: M, f: F) -> Result<Message> + where F: FnOnce(CreateMessage) -> CreateMessage, M: Into<MessageId> { + let 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))); + } + } + } + + rest::edit_message(self.0, message_id.into().0, &Value::Object(map)) + } + + /// Search the cache for the channel with the Id. + #[cfg(feature="cache")] + pub fn find(&self) -> Option<Channel> { + CACHE.read().unwrap().get_channel(*self) + } + + /// 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); + } + } + + 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]: permissions/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]: permissions/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)) + } + + /// Retrieves the channel's webhooks. + /// + /// **Note**: Requires the [Manage Webhooks] permission. + /// + /// [Manage Webhooks]: permissions/constant.MANAGE_WEBHOOKS.html + #[inline] + pub fn get_webhooks(&self) -> Result<Vec<Webhook>> { + rest::get_channel_webhooks(self.0) + } + + /// Pins a [`Message`] to the channel. + /// + /// [`Message`]: struct.Message.html + #[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. + /// + /// [`Message`]: struct.Message.html + #[inline] + pub fn pins(&self) -> Result<Vec<Message>> { + rest::get_pins(self.0) + } + + /// Sends a message with just the given message content in the channel. + /// + /// # 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. + /// + /// [`ChannelId`]: ../model/struct.ChannelId.html + /// [`ClientError::MessageTooLong`]: enum.ClientError.html#variant.MessageTooLong + #[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. + /// + /// 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. + /// + /// The [Attach Files] and [Send Messages] permissions are required. + /// + /// **Note**: Message contents must be under 2000 unicode code points. + /// + /// # Examples + /// + /// Send a file with the filename `my_file.jpg`: + /// + /// ```rust,no_run + /// use serenity::model::ChannelId; + /// use std::fs::File; + /// + /// let channel_id = ChannelId(7); + /// let filename = "my_file.jpg"; + /// let file = File::open(filename).unwrap(); + /// + /// let _ = channel_id.send_file(file, filename, |m| m.content("a file")); + /// ``` + /// + /// # 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. + /// + /// **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) + } +} + +impl From<Channel> for ChannelId { + /// Gets the Id of a `Channel`. + fn from(channel: Channel) -> ChannelId { + match channel { + Channel::Group(group) => group.read().unwrap().channel_id, + Channel::Guild(ch) => ch.read().unwrap().id, + Channel::Private(ch) => ch.read().unwrap().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 Display for ChannelId { + fn fmt(&self, f: &mut Formatter) -> FmtResult { + Display::fmt(&self.0, f) + } +} |