use chrono::{DateTime, FixedOffset}; use model::prelude::*; #[cfg(feature = "model")] use builder::{ CreateMessage, EditMessage, GetMessages }; #[cfg(feature = "model")] use http::{self, AttachmentType}; #[cfg(feature = "model")] use internal::RwLockExt; #[cfg(feature = "model")] use std::borrow::Cow; #[cfg(feature = "model")] use std::fmt::Write as FmtWrite; /// A group channel - potentially including other [`User`]s - separate from a /// [`Guild`]. /// /// [`Guild`]: struct.Guild.html /// [`User`]: struct.User.html #[derive(Clone, Debug, Deserialize, Serialize)] pub struct Group { /// The Id of the group channel. #[serde(rename = "id")] pub channel_id: ChannelId, /// The optional icon of the group channel. pub icon: Option, /// The Id of the last message sent. pub last_message_id: Option, /// Timestamp of the latest pinned message. pub last_pin_timestamp: Option>, /// The name of the group channel. pub name: Option, /// The Id of the group owner. pub owner_id: UserId, /// A map of the group's recipients. #[serde(deserialize_with = "deserialize_users", serialize_with = "serialize_users")] pub recipients: HashMap>>, } #[cfg(feature = "model")] impl Group { /// Adds the given user to the group. If the user is already in the group, /// then nothing is done. /// /// Refer to [`http::add_group_recipient`] for more information. /// /// **Note**: Groups have a limit of 10 recipients, including the current /// user. /// /// [`http::add_group_recipient`]: ../http/fn.add_group_recipient.html #[inline] pub fn add_recipient>(&self, user: U) -> Result<()> { self._add_recipient(user.into()) } fn _add_recipient(&self, user: UserId) -> Result<()> { // If the group already contains the recipient, do nothing. if self.recipients.contains_key(&user) { return Ok(()); } http::add_group_recipient(self.channel_id.0, user.0) } /// Broadcasts that the current user is typing in the group. #[inline] pub fn broadcast_typing(&self) -> Result<()> { self.channel_id.broadcast_typing() } /// 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(&self, message_id: M, reaction_type: R) -> Result<()> where M: Into, R: Into { self.channel_id.create_reaction(message_id, reaction_type) } /// 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**: Messages that are older than 2 weeks can't be deleted using /// this method. /// /// # Errors /// /// Returns [`ModelError::BulkDeleteAmount`] if an attempt was made to /// delete either 0 or more than 100 messages. /// /// [`Channel::delete_messages`]: enum.Channel.html#method.delete_messages /// [`ModelError::BulkDeleteAmount`]: ../enum.ModelError.html#variant.BulkDeleteAmount /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html #[inline] pub fn delete_messages, It: IntoIterator>(&self, message_ids: It) -> Result<()> { self.channel_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.channel_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(&self, message_id: M, user_id: Option, reaction_type: R) -> Result<()> where M: Into, R: Into { self.channel_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 [`EditMessage`] for more information /// regarding message restrictions and requirements. /// /// **Note**: Requires that the current user be the author of the message. /// /// # Errors /// /// Returns a [`ModelError::MessageTooLong`] if the content of the message /// is over the [`the limit`], containing the number of unicode code points /// over the limit. /// /// [`ModelError::MessageTooLong`]: enum.ModelError.html#variant.MessageTooLong /// [`EditMessage`]: ../builder/struct.EditMessage.html /// [`Message`]: struct.Message.html /// [`the limit`]: ../builder/struct.EditMessage.html#method.content #[inline] pub fn edit_message(&self, message_id: M, f: F) -> Result where F: FnOnce(EditMessage) -> EditMessage, M: Into { self.channel_id.edit_message(message_id, f) } /// Returns the formatted URI of the group's icon if one exists. pub fn icon_url(&self) -> Option { self.icon.as_ref().map(|icon| { format!(cdn!("/channel-icons/{}/{}.webp"), self.channel_id, icon) }) } /// Determines if the channel is NSFW. /// /// Refer to [`utils::is_nsfw`] for more details. /// /// **Note**: This method is for consistency. This will always return /// `false`, due to groups not being considered NSFW. /// /// [`utils::is_nsfw`]: ../../utils/fn.is_nsfw.html #[inline] pub fn is_nsfw(&self) -> bool { false } /// Leaves the group. #[inline] pub fn leave(&self) -> Result { http::leave_group(self.channel_id.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 message>(&self, message_id: M) -> Result { self.channel_id.message(message_id) } /// Gets messages from the channel. /// /// Requires the [Read Message History] permission. /// /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html #[inline] pub fn messages(&self, f: F) -> Result> where F: FnOnce(GetMessages) -> GetMessages { self.channel_id.messages(f) } /// Generates a name for the group. /// /// If there are no recipients in the group, the name will be "Empty Group". /// Otherwise, the name is generated in a Comma Separated Value list, such /// as "person 1, person 2, person 3". pub fn name(&self) -> Cow { match self.name { Some(ref name) => Cow::Borrowed(name), None => { let mut name = match self.recipients.values().nth(0) { Some(recipient) => recipient.with(|c| c.name.clone()), None => return Cow::Borrowed("Empty Group"), }; for recipient in self.recipients.values().skip(1) { let _ = write!(name, ", {}", recipient.with(|r| r.name.clone())); } Cow::Owned(name) }, } } /// Retrieves the list of messages that have been pinned in the group. #[inline] pub fn pins(&self) -> Result> { self.channel_id.pins() } /// Gets the list of [`User`]s who have reacted to a [`Message`] with a /// certain [`Emoji`]. /// /// Refer to [`Channel::reaction_users`] for more information. /// /// **Note**: Requires the [Read Message History] permission. /// /// [`Channel::reaction_users`]: enum.Channel.html#method.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 reaction_users( &self, message_id: M, reaction_type: R, limit: Option, after: U, ) -> Result> where M: Into, R: Into, U: Into> { self.channel_id.reaction_users(message_id, reaction_type, limit, after) } /// 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. #[inline] pub fn remove_recipient>(&self, user: U) -> Result<()> { self._remove_recipient(user.into()) } fn _remove_recipient(&self, user: UserId) -> Result<()> { // If the group does not contain the recipient already, do nothing. if !self.recipients.contains_key(&user) { return Ok(()); } http::remove_group_recipient(self.channel_id.0, user.0) } /// Sends a message with just the given message content in the channel. /// /// # Errors /// /// Returns a [`ModelError::MessageTooLong`] if the content of the message /// is over the above limit, containing the number of unicode code points /// over the limit. /// /// [`ChannelId`]: ../model/id/struct.ChannelId.html /// [`ModelError::MessageTooLong`]: enum.ModelError.html#variant.MessageTooLong #[inline] pub fn say(&self, content: &str) -> Result { self.channel_id.say(content) } /// Sends (a) file(s) along with optional message contents. /// /// Refer to [`ChannelId::send_files`] 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_files`]: struct.ChannelId.html#method.send_files /// [`ClientError::MessageTooLong`]: ../client/enum.ClientError.html#variant.MessageTooLong /// [Attach Files]: permissions/constant.ATTACH_FILES.html /// [Send Messages]: permissions/constant.SEND_MESSAGES.html #[inline] pub fn send_files<'a, F, T, It: IntoIterator>(&self, files: It, f: F) -> Result where F: FnOnce(CreateMessage) -> CreateMessage, T: Into> { self.channel_id.send_files(files, f) } /// Sends a message to the group with the given content. /// /// Refer to the documentation for [`CreateMessage`] for more information /// regarding message restrictions and requirements. /// /// **Note**: Requires the [Send Messages] permission. /// /// [`CreateMessage`]: ../builder/struct.CreateMessage.html /// [Send Messages]: permissions/constant.SEND_MESSAGES.html #[inline] pub fn send_message CreateMessage>(&self, f: F) -> Result { self.channel_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>(&self, message_id: M) -> Result<()> { self.channel_id.unpin(message_id) } }