diff options
| author | Zeyla Hellyer <[email protected]> | 2017-03-25 15:41:47 -0700 |
|---|---|---|
| committer | Zeyla Hellyer <[email protected]> | 2017-03-25 15:41:47 -0700 |
| commit | 9114963daf708cfaeaf54d8c788206ccfbae5df8 (patch) | |
| tree | 08d6aba5b8ad40189b312865ac776bb6fa30c45d /src/model/channel/mod.rs | |
| parent | Add slightly more documentation (diff) | |
| download | serenity-9114963daf708cfaeaf54d8c788206ccfbae5df8.tar.xz serenity-9114963daf708cfaeaf54d8c788206ccfbae5df8.zip | |
Rework the models directory
Diffstat (limited to 'src/model/channel/mod.rs')
| -rw-r--r-- | src/model/channel/mod.rs | 415 |
1 files changed, 415 insertions, 0 deletions
diff --git a/src/model/channel/mod.rs b/src/model/channel/mod.rs new file mode 100644 index 0000000..ff12084 --- /dev/null +++ b/src/model/channel/mod.rs @@ -0,0 +1,415 @@ +mod attachment; +mod channel_id; +mod embed; +mod group; +mod guild_channel; +mod message; +mod private_channel; +mod reaction; + +pub use self::attachment::*; +pub use self::channel_id::*; +pub use self::embed::*; +pub use self::group::*; +pub use self::guild_channel::*; +pub use self::message::*; +pub use self::private_channel::*; +pub use self::reaction::*; + +use std::fmt::{Display, Formatter, Result as FmtResult}; +use std::io::Read; +use ::client::CACHE; +use ::model::*; +use ::utils::builder::{CreateMessage, GetMessages, Search}; + +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`]: ../client/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)?; + match req!(map.get("type").and_then(|x| x.as_u64())) { + 0 | 2 => GuildChannel::decode(Value::Object(map)) + .map(|x| Channel::Guild(Arc::new(RwLock::new(x)))), + 1 => PrivateChannel::decode(Value::Object(map)) + .map(|x| Channel::Private(Arc::new(RwLock::new(x)))), + 3 => Group::decode(Value::Object(map)) + .map(|x| Channel::Group(Arc::new(RwLock::new(x)))), + other => Err(Error::Decode("Expected value Channel type", + Value::U64(other))), + } + } + + /// Deletes the inner channel. + /// + /// **Note**: There is no real function as _deleting_ a [`Group`]. The + /// closest functionality is leaving it. + /// + /// [`Group`]: struct.Group.html + pub fn delete(&self) -> Result<()> { + match *self { + Channel::Group(ref group) => { + let _ = group.read().unwrap().leave()?; + }, + Channel::Guild(ref public_channel) => { + let _ = public_channel.read().unwrap().delete()?; + }, + Channel::Private(ref private_channel) => { + let _ = private_channel.read().unwrap().delete()?; + }, + } + + 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. + /// + /// [`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) + } + + /// 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 + #[inline] + pub fn edit_message<F, M>(&self, message_id: M, f: F) -> Result<Message> + where F: FnOnce(CreateMessage) -> CreateMessage, M: Into<MessageId> { + self.id().edit_message(message_id, f) + } + + /// 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> { + self.id().get_message(message_id) + } + + /// Gets messages from the channel. + /// + /// Requires the [Read Message History] permission. + /// + /// # Examples + /// + /// ```rust,ignore + /// use serenity::model::MessageId; + /// + /// let id = MessageId(81392407232380928); + /// + /// // Maximum is 100. + /// let _messages = channel.get_messages(|g| g.after(id).limit(100)); + /// ``` + /// + /// [Read Message History]: permissions/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`]. + /// + /// [`Group`]: struct.Group.html + /// [`GuildChannel`]: struct.GuildChannel.html + /// [`PrivateChannel`]: struct.PrivateChannel.html + pub fn id(&self) -> ChannelId { + match *self { + Channel::Group(ref group) => group.read().unwrap().channel_id, + Channel::Guild(ref channel) => channel.read().unwrap().id, + Channel::Private(ref channel) => channel.read().unwrap().id, + } + } + + /// 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.id().say(content) + } + + /// Performs a search request to the API for the inner channel's + /// [`Message`]s. + /// + /// Refer to the documentation for the [`Search`] builder for examples and + /// more information. + /// + /// **Note**: Bot users can not search. + /// + /// # Errors + /// + /// If the `cache` is enabled, returns a + /// [`ClientError::InvalidOperationAsBot`] if the current user is a bot. + /// + /// [`ClientError::InvalidOperationAsBot`]: ../client/enum.ClientError.html#variant.InvalidOperationAsBot + /// [`Message`]: struct.Message.html + /// [`Search`]: ../utils/builder/struct.Search.html + pub fn search<F>(&self, f: F) -> Result<SearchResult> + where F: FnOnce(Search) -> Search { + #[cfg(feature="cache")] + { + if CACHE.read().unwrap().user.bot { + return Err(Error::Client(ClientError::InvalidOperationAsBot)); + } + } + + self.id().search(f) + } + + /// Sends a file along with optional message contents. The filename _must_ + /// be specified. + /// + /// Refer to [`ChannelId::send_file`] for examples and more information. + /// + /// 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. + /// + /// [`ChannelId::send_file`]: struct.ChannelId.html#method.send_file + /// [`ClientError::MessageTooLong`]: ../client/enum.ClientError.html#variant.MessageTooLong + /// [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 { + self.id().send_file(file, filename, f) + } + + /// Sends a message to the channel. + /// + /// Refer to the documentation for [`CreateMessage`] for more information + /// regarding message restrictions and requirements. + /// + /// 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 + #[inline] + pub fn send_message<F>(&self, f: F) -> Result<Message> + where F: FnOnce(CreateMessage) -> CreateMessage { + self.id().send_message(f) + } + + /// 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) + } +} + +impl Display for Channel { + /// Formats the channel into a "mentioned" string. + /// + /// This will return a different format for each type of channel: + /// + /// - [`Group`]s: the generated name retrievable via [`Group::name`]; + /// - [`PrivateChannel`]s: the recipient's name; + /// - [`GuildChannel`]s: a string mentioning the channel that users who can + /// see the channel can click on. + /// + /// [`Group`]: struct.Group.html + /// [`Group::name`]: struct.Group.html#method.name + /// [`GuildChannel`]: struct.GuildChannel.html + /// [`PrivateChannel`]: struct.PrivateChannel.html + fn fmt(&self, f: &mut Formatter) -> FmtResult { + match *self { + Channel::Group(ref group) => { + Display::fmt(&group.read().unwrap().name(), f) + }, + Channel::Guild(ref ch) => { + Display::fmt(&ch.read().unwrap().id.mention(), f) + }, + Channel::Private(ref ch) => { + let channel = ch.read().unwrap(); + let recipient = channel.recipient.read().unwrap(); + + Display::fmt(&recipient.name, f) + }, + } + } +} + +impl PermissionOverwrite { + #[doc(hidden)] + pub fn decode(value: Value) -> Result<PermissionOverwrite> { + let mut map = into_map(value)?; + let id = remove(&mut map, "id").and_then(decode_id)?; + let kind = remove(&mut map, "type").and_then(into_string)?; + let kind = match &*kind { + "member" => PermissionOverwriteType::Member(UserId(id)), + "role" => PermissionOverwriteType::Role(RoleId(id)), + _ => return Err(Error::Decode("Expected valid PermissionOverwrite type", Value::String(kind))), + }; + + Ok(PermissionOverwrite { + kind: kind, + allow: remove(&mut map, "allow").and_then(Permissions::decode)?, + deny: remove(&mut map, "deny").and_then(Permissions::decode)?, + }) + } +} |