aboutsummaryrefslogtreecommitdiff
path: root/src/model
diff options
context:
space:
mode:
authorZeyla Hellyer <[email protected]>2018-03-25 19:24:19 -0700
committerZeyla Hellyer <[email protected]>2018-03-25 19:24:19 -0700
commit461ebe03d58d1ec78ed5addb65e688d63ecfcf45 (patch)
tree84475e0717d089551b7e615cdf7d2cfcbff32d57 /src/model
parentRewrite the library to use Futures (diff)
downloadserenity-461ebe03d58d1ec78ed5addb65e688d63ecfcf45.tar.xz
serenity-461ebe03d58d1ec78ed5addb65e688d63ecfcf45.zip
Remove cache/http methods on structs
Diffstat (limited to 'src/model')
-rw-r--r--src/model/channel/attachment.rs1
-rw-r--r--src/model/channel/channel_category.rs87
-rw-r--r--src/model/channel/embed.rs7
-rw-r--r--src/model/channel/group.rs319
-rw-r--r--src/model/channel/guild_channel.rs599
-rw-r--r--src/model/channel/message.rs471
-rw-r--r--src/model/channel/mod.rs285
-rw-r--r--src/model/channel/private_channel.rs295
-rw-r--r--src/model/channel/reaction.rs148
-rw-r--r--src/model/gateway.rs1
-rw-r--r--src/model/guild/emoji.rs139
-rw-r--r--src/model/guild/guild_id.rs1
-rw-r--r--src/model/guild/member.rs384
-rw-r--r--src/model/guild/mod.rs819
-rw-r--r--src/model/guild/partial_guild.rs406
-rw-r--r--src/model/guild/role.rs74
-rw-r--r--src/model/invite.rs80
-rw-r--r--src/model/mod.rs3
-rw-r--r--src/model/permissions.rs1
-rw-r--r--src/model/user.rs385
-rw-r--r--src/model/utils.rs11
-rw-r--r--src/model/webhook.rs145
22 files changed, 14 insertions, 4647 deletions
diff --git a/src/model/channel/attachment.rs b/src/model/channel/attachment.rs
index 65df67e..8e3f149 100644
--- a/src/model/channel/attachment.rs
+++ b/src/model/channel/attachment.rs
@@ -20,7 +20,6 @@ pub struct Attachment {
pub width: Option<u64>,
}
-#[cfg(feature = "model")]
impl Attachment {
/// If this attachment is an image, then a tuple of the width and height
/// in pixels is returned.
diff --git a/src/model/channel/channel_category.rs b/src/model/channel/channel_category.rs
index 451d550..0fd1a69 100644
--- a/src/model/channel/channel_category.rs
+++ b/src/model/channel/channel_category.rs
@@ -1,11 +1,5 @@
-use client::Client;
-use futures::{Future, future};
use model::prelude::*;
-use std::rc::Rc;
-use ::FutureResult;
-#[cfg(all(feature = "builder", feature = "model"))]
-use builder::EditChannel;
#[cfg(feature = "utils")]
use utils as serenity_utils;
@@ -37,90 +31,9 @@ pub struct ChannelCategory {
///
/// [`GuildChannel`]: struct.GuildChannel.html
pub permission_overwrites: Vec<PermissionOverwrite>,
- #[serde(skip)]
- pub(crate) client: Option<Rc<Client>>,
}
impl ChannelCategory {
- /// Adds a permission overwrite to the category's channels.
- #[inline]
- pub fn create_permission(&self, target: &PermissionOverwrite) -> FutureResult<()> {
- ftryopt!(self.client)
- .http
- .create_permission(self.id.0, target)
- }
-
- /// Deletes all permission overrides in the category from the channels.
- ///
- /// **Note**: Requires the [Manage Channel] permission.
- ///
- /// [Manage Channel]: permissions/constant.MANAGE_CHANNELS.html
- #[inline]
- pub fn delete_permission(&self, permission_type: PermissionOverwriteType)
- -> FutureResult<()> {
- let id = match permission_type {
- PermissionOverwriteType::Member(id) => id.0,
- PermissionOverwriteType::Role(id) => id.0,
- };
-
- let done = ftryopt!(self.client)
- .http
- .delete_permission(self.id.0, id);
-
- Box::new(done)
- }
-
- /// Deletes this category.
- #[inline]
- pub fn delete(&self) -> FutureResult<()> {
- let client = ftryopt!(self.client);
-
- #[cfg(feature = "cache")]
- {
- let req = Permissions::MANAGE_CHANNELS;
-
- if !ftry!(client.cache.borrow().user_has_perms(self.id, req)) {
- return Box::new(future::err(Error::Model(
- ModelError::InvalidPermissions(req),
- )));
- }
- }
-
- let done = client.http.delete_channel(self.id.0).map(|_| ());
-
- Box::new(done)
- }
-
- /// Modifies the category's settings, such as its position or name.
- ///
- /// Refer to `EditChannel`s documentation for a full list of methods.
- ///
- /// # Examples
- ///
- /// Change a voice channels name and bitrate:
- ///
- /// ```rust,ignore
- /// category.edit(|c| c.name("test").bitrate(86400));
- /// ```
- #[cfg(all(feature = "builder", feature = "model", feature = "utils"))]
- pub fn edit<F: FnOnce(EditChannel) -> EditChannel>(&self, f: F)
- -> FutureResult<GuildChannel> {
- let client = ftryopt!(self.client);
-
- #[cfg(feature = "cache")]
- {
- let req = Permissions::MANAGE_CHANNELS;
-
- if !ftry!(client.cache.borrow().user_has_perms(self.id, req)) {
- return Box::new(future::err(Error::Model(
- ModelError::InvalidPermissions(req),
- )));
- }
- }
-
- ftryopt!(self.client).http.edit_channel(self.id.0, f)
- }
-
#[cfg(feature = "utils")]
#[inline]
pub fn is_nsfw(&self) -> bool {
diff --git a/src/model/channel/embed.rs b/src/model/channel/embed.rs
index 8837a8d..79dee11 100644
--- a/src/model/channel/embed.rs
+++ b/src/model/channel/embed.rs
@@ -1,11 +1,9 @@
-#[cfg(feature = "model")]
use builder::CreateEmbed;
-#[cfg(feature = "model")]
use internal::prelude::*;
+use utils;
+
#[cfg(feature = "utils")]
use utils::Colour;
-#[cfg(feature = "model")]
-use utils;
/// Represents a rich embed which allows using richer markdown, multiple fields
/// and more. This was heavily inspired by [slack's attachments].
@@ -65,7 +63,6 @@ pub struct Embed {
pub video: Option<EmbedVideo>,
}
-#[cfg(feature = "model")]
impl Embed {
/// Creates a fake Embed, giving back a `serde_json` map.
///
diff --git a/src/model/channel/group.rs b/src/model/channel/group.rs
index f55a9dd..6573052 100644
--- a/src/model/channel/group.rs
+++ b/src/model/channel/group.rs
@@ -1,17 +1,9 @@
use chrono::{DateTime, FixedOffset};
-use client::Client;
-use futures::{Future, future};
use model::prelude::*;
-use std::cell::RefCell;
-use std::rc::Rc;
-use ::FutureResult;
-
-// #[cfg(feature = "model")]
-use builder::{CreateMessage, EditMessage, GetMessages};
-#[cfg(feature = "model")]
use std::borrow::Cow;
-#[cfg(feature = "model")]
+use std::cell::RefCell;
use std::fmt::Write as FmtWrite;
+use std::rc::Rc;
/// A group channel - potentially including other [`User`]s - separate from a
/// [`Guild`].
@@ -37,162 +29,9 @@ pub struct Group {
#[serde(deserialize_with = "deserialize_users",
serialize_with = "serialize_users")]
pub recipients: HashMap<UserId, Rc<RefCell<User>>>,
- #[serde(skip)]
- pub(crate) client: Option<Rc<Client>>,
}
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
- pub fn add_recipient<U: Into<UserId>>(&self, user: U) -> FutureResult<()> {
- let user = user.into();
-
- // If the group already contains the recipient, do nothing.
- if self.recipients.contains_key(&user) {
- return Box::new(future::ok(()));
- }
-
- ftryopt!(self.client)
- .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) -> FutureResult<()> {
- ftryopt!(self.client).http.broadcast_typing(self.channel_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
- #[inline]
- pub fn create_reaction<M, R>(&self, message_id: M, reaction_type: R)
- -> FutureResult<()>
- where M: Into<MessageId>, R: Into<ReactionType> {
- ftryopt!(self.client).http.create_reaction(
- self.channel_id.0,
- message_id.into().0,
- &reaction_type.into(),
- )
- }
-
- /// 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<T: AsRef<MessageId>, It: IntoIterator<Item=T>>(
- &self,
- message_ids: It,
- ) -> FutureResult<()> {
- ftryopt!(self.client).http.delete_messages(
- self.channel_id.0,
- 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)
- -> FutureResult<()> {
- let overwrite_id = match permission_type {
- PermissionOverwriteType::Member(id) => id.0,
- PermissionOverwriteType::Role(id) => id.0,
- };
-
- ftryopt!(self.client).http.delete_permission(
- self.channel_id.0,
- overwrite_id,
- )
- }
-
- /// 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,
- ) -> FutureResult<()> where M: Into<MessageId>, R: Into<ReactionType> {
- ftryopt!(self.client).http.delete_reaction(
- self.channel_id.0,
- message_id.into().0,
- user_id.map(|x| x.0),
- &reaction_type.into(),
- )
- }
-
- /// 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<F, M>(&self, message_id: M, f: F)
- -> FutureResult<Message>
- where F: FnOnce(EditMessage) -> EditMessage, M: Into<MessageId> {
- ftryopt!(self.client).http.edit_message(
- self.channel_id.0,
- message_id.into().0,
- f,
- )
- }
-
/// Returns the formatted URI of the group's icon if one exists.
pub fn icon_url(&self) -> Option<String> {
self.icon.as_ref().map(|icon| {
@@ -211,33 +50,6 @@ impl Group {
#[inline]
pub fn is_nsfw(&self) -> bool { false }
- /// Leaves the group.
- #[inline]
- pub fn leave(&self) -> FutureResult<()> {
- ftryopt!(self.client).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<M: Into<MessageId>>(&self, message_id: M) -> FutureResult<Message> {
- ftryopt!(self.client).http.get_message(self.channel_id.0, message_id.into().0)
- }
-
- /// Gets messages from the channel.
- ///
- /// Requires the [Read Message History] permission.
- ///
- /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
- #[inline]
- pub fn messages<'a, F: FnOnce(GetMessages) -> GetMessages>(&'a self, f: F)
- -> Box<Future<Item = Vec<Message>, Error = Error> + 'a> {
- ftryopt!(self.client).http.get_messages(self.channel_id.0, f)
- }
-
/// Generates a name for the group.
///
/// If there are no recipients in the group, the name will be "Empty Group".
@@ -262,131 +74,4 @@ impl Group {
},
}
}
-
- /// Retrieves the list of messages that have been pinned in the group.
- #[inline]
- pub fn pins(&self) -> FutureResult<Vec<Message>> {
- ftryopt!(self.client).http.get_pins(self.channel_id.0)
- }
-
- /// 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<M, R, U>(
- &self,
- message_id: M,
- reaction_type: R,
- limit: Option<u8>,
- after: U,
- ) -> FutureResult<Vec<User>>
- where M: Into<MessageId>, R: Into<ReactionType>, U: Into<Option<UserId>> {
- ftryopt!(self.client).http.get_reaction_users(
- self.channel_id.0,
- message_id.into().0,
- &reaction_type.into(),
- limit,
- after.into().map(|x| x.0),
- )
- }
-
- /// 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.
- pub fn remove_recipient<U>(&self, user: U) -> FutureResult<()>
- where U: Into<UserId> {
- let user = user.into();
-
- // If the group does not contain the recipient already, do nothing.
- if !self.recipients.contains_key(&user) {
- return Box::new(future::ok(()));
- }
-
- ftryopt!(self.client).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) -> FutureResult<Message> {
- ftryopt!(self.client).http.send_message(self.channel_id.0, |f| f
- .content(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
- // todo
- // #[inline]
- // pub fn send_files<'a, F, T, It>(&self, files: It, f: F)
- // -> FutureResult<Message>
- // where F: FnOnce(CreateMessage) -> CreateMessage,
- // T: Into<AttachmentType<'a>>,
- // It: IntoIterator<Item=T> {
- // ftryopt!(self.client).http.send_files(self.channel_id.0, 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<F>(&self, f: F) -> FutureResult<Message>
- where F: FnOnce(CreateMessage) -> CreateMessage {
- ftryopt!(self.client).http.send_message(self.channel_id.0, 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) -> FutureResult<()> {
- ftryopt!(self.client)
- .http
- .unpin_message(self.channel_id.0, message_id.into().0)
- }
}
diff --git a/src/model/channel/guild_channel.rs b/src/model/channel/guild_channel.rs
index ea99377..0ec65eb 100644
--- a/src/model/channel/guild_channel.rs
+++ b/src/model/channel/guild_channel.rs
@@ -1,17 +1,8 @@
use chrono::{DateTime, FixedOffset};
-use futures::{Future, future};
use model::prelude::*;
-use std::cell::RefCell;
-use super::super::WrappedClient;
-use ::FutureResult;
-#[cfg(feature = "model")]
-use builder::{CreateInvite, CreateMessage, EditChannel, EditMessage, GetMessages};
-#[cfg(all(feature = "cache", feature = "model"))]
-use internal::prelude::*;
-#[cfg(feature = "model")]
use std::fmt::{Display, Formatter, Result as FmtResult};
-#[cfg(all(feature = "model", feature = "utils"))]
+#[cfg(feature = "utils")]
use utils as serenity_utils;
/// Represents a guild's text or voice channel. Some methods are available only
@@ -75,326 +66,9 @@ pub struct GuildChannel {
// default to `false`.
#[serde(default)]
pub nsfw: bool,
- #[serde(skip)]
- pub(crate) client: WrappedClient,
}
-#[cfg(feature = "model")]
impl GuildChannel {
- /// Broadcasts to the channel that the current user is typing.
- ///
- /// For bots, this is a good indicator for long-running commands.
- ///
- /// **Note**: Requires the [Send Messages] permission.
- ///
- /// # Errors
- ///
- /// Returns a [`ModelError::InvalidPermissions`] if the current user does
- /// not have the required permissions.
- ///
- /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
- /// [Send Messages]: permissions/constant.SEND_MESSAGES.html
- pub fn broadcast_typing(&self) -> FutureResult<()> {
- ftryopt!(self.client).http.broadcast_typing(self.id.0)
- }
-
- /// Creates an invite leading to the given channel.
- ///
- /// # Examples
- ///
- /// Create an invite that can only be used 5 times:
- ///
- /// ```rust,ignore
- /// let invite = channel.create_invite(|i| i.max_uses(5));
- /// ```
- #[cfg(feature = "utils")]
- pub fn create_invite<F>(&self, f: F) -> FutureResult<RichInvite>
- where F: FnOnce(CreateInvite) -> CreateInvite {
- let client = ftryopt!(self.client);
-
- #[cfg(feature = "cache")]
- {
- let req = Permissions::CREATE_INVITE;
-
- if !ftry!(client.cache.borrow().user_has_perms(self.id, req)) {
- return Box::new(future::err(Error::Model(
- ModelError::InvalidPermissions(req),
- )));
- }
- }
-
- client.http.create_invite(self.id.0, f)
- }
-
- /// 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,no_run
- /// # use serenity::model::id::{ChannelId, UserId};
- /// # use std::error::Error;
- /// #
- /// # fn try_main() -> Result<(), Box<Error>> {
- /// # let (channel_id, user_id) = (ChannelId(0), UserId(0));
- /// #
- /// use serenity::model::channel::{
- /// PermissionOverwrite,
- /// PermissionOverwriteType,
- /// };
- /// use serenity::model::{ModelError, Permissions};
- /// use serenity::CACHE;
- ///
- /// 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 cache = CACHE.read();
- /// let channel = cache
- /// .guild_channel(channel_id)
- /// .ok_or(ModelError::ItemMissing)?;
- ///
- /// channel.read().create_permission(&overwrite)?;
- /// # Ok(())
- /// # }
- /// #
- /// # fn main() {
- /// # try_main().unwrap();
- /// # }
- /// ```
- ///
- /// 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,no_run
- /// # use serenity::model::id::{ChannelId, UserId};
- /// # use std::error::Error;
- /// #
- /// # fn try_main() -> Result<(), Box<Error>> {
- /// # let (channel_id, user_id) = (ChannelId(0), UserId(0));
- /// #
- /// use serenity::model::channel::{
- /// PermissionOverwrite,
- /// PermissionOverwriteType,
- /// };
- /// use serenity::model::{ModelError, Permissions};
- /// use serenity::CACHE;
- ///
- /// 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 cache = CACHE.read();
- /// let channel = cache
- /// .guild_channel(channel_id)
- /// .ok_or(ModelError::ItemMissing)?;
- ///
- /// channel.read().create_permission(&overwrite)?;
- /// # Ok(())
- /// # }
- /// #
- /// # fn main() {
- /// # try_main().unwrap();
- /// # }
- /// ```
- ///
- /// [`Channel`]: enum.Channel.html
- /// [`Member`]: struct.Member.html
- /// [`PermissionOverwrite`]: struct.PermissionOverwrite.html
- /// [`PermissionOverwrite::Member`]: struct.PermissionOverwrite.html#variant.Member
- /// [`PermissionOverwrite::Role`]: struct.PermissionOverwrite.html#variant.Role
- /// [`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 Messages]: permissions/constant.SEND_MESSAGES.html
- /// [Send TTS Messages]: permissions/constant.SEND_TTS_MESSAGES.html
- #[inline]
- pub fn create_permission(&self, target: &PermissionOverwrite)
- -> FutureResult<()> {
- ftryopt!(self.client).http.create_permission(self.id.0, target)
- }
-
- /// Deletes this channel, returning the channel on a successful deletion.
- pub fn delete(&self) -> FutureResult<Channel> {
- let client = ftryopt!(self.client);
-
- #[cfg(feature = "cache")]
- {
- let req = Permissions::MANAGE_CHANNELS;
-
- if !ftry!(client.cache.borrow().user_has_perms(self.id, req)) {
- return Box::new(future::err(Error::Model(
- ModelError::InvalidPermissions(req),
- )));
- }
- }
-
- client.http.delete_channel(self.id.0)
- }
-
- /// 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<T, It>(&self, message_ids: It) -> FutureResult<()>
- where T: AsRef<MessageId>, It: IntoIterator<Item=T> {
- ftryopt!(self.client).http.delete_messages(self.id.0, 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)
- -> FutureResult<()> {
- let overwrite_id = match permission_type {
- PermissionOverwriteType::Member(id) => id.0,
- PermissionOverwriteType::Role(id) => id.0,
- };
-
- ftryopt!(self.client).http.delete_permission(self.id.0, overwrite_id)
- }
-
- /// 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,
- ) -> FutureResult<()> where M: Into<MessageId>, R: Into<ReactionType> {
- ftryopt!(self.client).http.delete_reaction(
- self.id.0,
- message_id.into().0,
- user_id.map(|x| x.0),
- &reaction_type.into(),
- )
- }
-
- /// Modifies a channel's settings, such as its position or name.
- ///
- /// Refer to `EditChannel`s documentation for a full list of methods.
- ///
- /// # Examples
- ///
- /// Change a voice channels name and bitrate:
- ///
- /// ```rust,ignore
- /// channel.edit(|c| c.name("test").bitrate(86400));
- /// ```
- #[cfg(feature = "utils")]
- pub fn edit<F: FnOnce(EditChannel) -> EditChannel>(&self, f: F)
- -> FutureResult<GuildChannel> {
- let client = ftryopt!(self.client);
-
- #[cfg(feature = "cache")]
- {
- let req = Permissions::MANAGE_CHANNELS;
-
- if !ftry!(client.cache.borrow().user_has_perms(self.id, req)) {
- return Box::new(future::err(Error::Model(
- ModelError::InvalidPermissions(req),
- )));
- }
- }
-
- client.http.edit_channel(self.id.0, f)
- }
-
- /// 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<F, M>(&self, message_id: M, f: F)
- -> FutureResult<Message>
- where F: FnOnce(EditMessage) -> EditMessage, M: Into<MessageId> {
- ftryopt!(self.client).http.edit_message(
- self.id.0,
- message_id.into().0,
- f,
- )
- }
-
- /// 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(feature = "cache")]
- pub fn guild(&self) -> Option<Rc<RefCell<Guild>>> {
- self.client.as_ref()?.cache.try_borrow().ok().and_then(|cache| {
- cache.guild(self.guild_id)
- })
- }
-
- /// Gets all of the channel's invites.
- ///
- /// Requires the [Manage Channels] permission.
- /// [Manage Channels]: permissions/constant.MANAGE_CHANNELS.html
- #[inline]
- pub fn invites(&self) -> FutureResult<Vec<RichInvite>> {
- ftryopt!(self.client).http.get_channel_invites(self.id.0)
- }
-
/// Determines if the channel is NSFW.
///
/// Refer to [`utils::is_nsfw`] for more details.
@@ -411,281 +85,10 @@ impl GuildChannel {
self.kind == ChannelType::Text && (self.nsfw || serenity_utils::is_nsfw(&self.name))
}
- /// 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<M: Into<MessageId>>(&self, message_id: M)
- -> FutureResult<Message> {
- ftryopt!(self.client).http.get_message(self.id.0, message_id.into().0)
- }
-
- /// Gets messages from the channel.
- ///
- /// Refer to [`Channel::messages`] for more information.
- ///
- /// Requires the [Read Message History] permission.
- ///
- /// [`Channel::messages`]: enum.Channel.html#method.messages
- /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
- #[inline]
- pub fn messages<'a, F: FnOnce(GetMessages) -> GetMessages>(&'a self, f: F)
- -> Box<Future<Item = Vec<Message>, Error = Error> + 'a> {
- ftryopt!(self.client).http.get_messages(self.id.0, f)
- }
-
/// Returns the name of the guild channel.
pub fn name(&self) -> &str { &self.name }
-
- /// Calculates the permissions of a member.
- ///
- /// The Id of the argument must be a [`Member`] of the [`Guild`] that the
- /// channel is in.
- ///
- /// # Examples
- ///
- /// Calculate the permissions of a [`User`] who posted a [`Message`] in a
- /// channel:
- ///
- /// ```rust,no_run
- /// use serenity::prelude::*;
- /// use serenity::model::prelude::*;
- /// struct Handler;
- ///
- /// use serenity::CACHE;
- ///
- /// impl EventHandler for Handler {
- /// fn message(&self, _: Context, msg: Message) {
- /// let channel = match CACHE.read().guild_channel(msg.channel_id) {
- /// Some(channel) => channel,
- /// None => return,
- /// };
- ///
- /// let permissions = channel.read().permissions_for(&msg.author).unwrap();
- ///
- /// println!("The user's permissions: {:?}", permissions);
- /// }
- /// }
- /// let mut client = Client::new("token", Handler).unwrap();
- ///
- /// client.start().unwrap();
- /// ```
- ///
- /// Check if the current user has the [Attach Files] and [Send Messages]
- /// permissions (note: serenity will automatically check this for; this is
- /// for demonstrative purposes):
- ///
- /// ```rust,no_run
- /// use serenity::CACHE;
- /// use serenity::prelude::*;
- /// use serenity::model::prelude::*;
- /// use std::fs::File;
- ///
- /// struct Handler;
- ///
- /// impl EventHandler for Handler {
- /// fn message(&self, _: Context, msg: Message) {
- /// let channel = match CACHE.read().guild_channel(msg.channel_id) {
- /// Some(channel) => channel,
- /// None => return,
- /// };
- ///
- /// let current_user_id = CACHE.read().user.id;
- /// let permissions =
- /// channel.read().permissions_for(current_user_id).unwrap();
- ///
- /// if !permissions.contains(Permissions::ATTACH_FILES | Permissions::SEND_MESSAGES) {
- /// return;
- /// }
- ///
- /// let file = match File::open("./cat.png") {
- /// Ok(file) => file,
- /// Err(why) => {
- /// println!("Err opening file: {:?}", why);
- ///
- /// return;
- /// },
- /// };
- ///
- /// let _ = msg.channel_id.send_files(vec![(&file, "cat.png")], |m|
- /// m.content("here's a cat"));
- /// }
- /// }
- ///
- /// let mut client = Client::new("token", Handler).unwrap();
- ///
- /// client.start().unwrap();
- /// ```
- ///
- /// # Errors
- ///
- /// Returns a [`ModelError::GuildNotFound`] if the channel's guild could
- /// not be found in the [`Cache`].
- ///
- /// [`Cache`]: ../cache/struct.Cache.html
- /// [`ModelError::GuildNotFound`]: enum.ModelError.html#variant.GuildNotFound
- /// [`Guild`]: struct.Guild.html
- /// [`Member`]: struct.Member.html
- /// [`Message`]: struct.Message.html
- /// [`User`]: struct.User.html
- /// [Attach Files]: permissions/constant.ATTACH_FILES.html
- /// [Send Messages]: permissions/constant.SEND_MESSAGES.html
- #[cfg(feature = "cache")]
- pub fn permissions_for<U: Into<UserId>>(&self, user_id: U)
- -> Result<Permissions> {
- self.guild()
- .ok_or_else(|| Error::Model(ModelError::GuildNotFound))
- .map(|g| g.borrow().permissions_in(self.id, user_id))
- }
-
- /// Pins a [`Message`] to the channel.
- #[inline]
- pub fn pin<M: Into<MessageId>>(&self, message_id: M) -> FutureResult<()> {
- ftryopt!(self.client).http.pin_message(self.id.0, message_id.into().0)
- }
-
- /// Gets all channel's pins.
- #[inline]
- pub fn pins(&self) -> FutureResult<Vec<Message>> {
- ftryopt!(self.client).http.get_pins(self.id.0)
- }
-
- /// 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
- pub fn reaction_users<M, R, U>(
- &self,
- message_id: M,
- reaction_type: R,
- limit: Option<u8>,
- after: U,
- ) -> FutureResult<Vec<User>>
- where M: Into<MessageId>, R: Into<ReactionType>, U: Into<Option<UserId>> {
- ftryopt!(self.client).http.get_reaction_users(
- self.id.0,
- message_id.into().0,
- &reaction_type.into(),
- limit,
- after.into().map(|x| x.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`]: struct.ChannelId.html
- /// [`ModelError::MessageTooLong`]: enum.ModelError.html#variant.MessageTooLong
- #[inline]
- pub fn say(&self, content: &str) -> FutureResult<Message> {
- ftryopt!(self.client)
- .http
- .send_message(self.id.0, |m| m.content(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
- // todo
- // #[inline]
- // pub fn send_files<'a, F, T, It>(&self, files: It, f: F)
- // -> FutureResult<Message>
- // where F: FnOnce(CreateMessage) -> CreateMessage,
- // T: Into<AttachmentType<'a>>,
- // It: IntoIterator<Item=T> {
- // ftryopt!(self.client).http.send_files(self.id.0, files, f)
- // }
-
- /// Sends a message to the channel with the given content.
- ///
- /// **Note**: This will only work when a [`Message`] is received.
- ///
- /// **Note**: Requires the [Send Messages] permission.
- ///
- /// # 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.
- ///
- /// Returns a [`ModelError::InvalidPermissions`] if the current user does
- /// not have the required permissions.
- ///
- /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
- /// [`ModelError::MessageTooLong`]: enum.ModelError.html#variant.MessageTooLong
- /// [`Message`]: struct.Message.html
- /// [Send Messages]: permissions/constant.SEND_MESSAGES.html
- pub fn send_message<F: FnOnce(CreateMessage) -> CreateMessage>(&self, f: F)
- -> FutureResult<Message> {
- let client = ftryopt!(self.client);
-
- #[cfg(feature = "cache")]
- {
- let req = Permissions::SEND_MESSAGES;
-
- if !ftry!(client.cache.borrow().user_has_perms(self.id, req)) {
- return Box::new(future::err(Error::Model(
- ModelError::InvalidPermissions(req),
- )));
- }
- }
-
- client.http.send_message(self.id.0, 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) -> FutureResult<()> {
- ftryopt!(self.client).http.unpin_message(self.id.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) -> FutureResult<Vec<Webhook>> {
- ftryopt!(self.client).http.get_channel_webhooks(self.id.0)
- }
}
-#[cfg(feature = "model")]
impl Display for GuildChannel {
/// Formats the channel, creating a mention of it.
fn fmt(&self, f: &mut Formatter) -> FmtResult { Display::fmt(&self.id.mention(), f) }
diff --git a/src/model/channel/message.rs b/src/model/channel/message.rs
index 97c0ab2..fc336df 100644
--- a/src/model/channel/message.rs
+++ b/src/model/channel/message.rs
@@ -1,20 +1,9 @@
//! Models relating to Discord channels.
use chrono::{DateTime, FixedOffset};
-use futures::future;
+use constants;
use model::prelude::*;
use serde_json::Value;
-use std::cell::RefCell;
-use std::rc::Rc;
-use super::super::WrappedClient;
-use ::FutureResult;
-
-#[cfg(feature = "model")]
-use builder::EditMessage;
-#[cfg(all(feature = "cache", feature = "model"))]
-use std::fmt::Write;
-#[cfg(feature = "model")]
-use constants;
/// A representation of a message over a guild's text channel, a group, or a
/// private channel.
@@ -66,183 +55,10 @@ pub struct Message {
pub tts: bool,
/// The Id of the webhook that sent this message, if one did.
pub webhook_id: Option<WebhookId>,
- #[serde(skip)]
- pub(crate) client: WrappedClient,
}
-#[cfg(feature = "model")]
impl Message {
- /// Retrieves the related channel located in the cache.
- ///
- /// Returns `None` if the channel is not in the cache.
- ///
- /// # Examples
- ///
- /// On command, print the name of the channel that a message took place in:
- ///
- /// ```rust,no_run
- /// # #[macro_use] extern crate serenity;
- /// #
- /// # fn main() {
- /// # use serenity::prelude::*;
- /// # struct Handler;
- /// #
- /// # impl EventHandler for Handler {}
- /// # let mut client = Client::new("token", Handler).unwrap();
- /// #
- /// use serenity::model::channel::Channel;
- /// use serenity::framework::StandardFramework;
- ///
- /// client.with_framework(StandardFramework::new()
- /// .configure(|c| c.prefix("~"))
- /// .cmd("channelname", channel_name));
- ///
- /// command!(channel_name(_ctx, msg) {
- /// let _ = match msg.channel() {
- /// Some(Channel::Category(c)) => msg.reply(&c.read().name),
- /// Some(Channel::Group(c)) => msg.reply(&c.read().name()),
- /// Some(Channel::Guild(c)) => msg.reply(&c.read().name),
- /// Some(Channel::Private(c)) => {
- /// let channel = c.read();
- /// let user = channel.recipient.read();
- ///
- /// msg.reply(&format!("DM with {}", user.name.clone()))
- /// },
- /// None => msg.reply("Unknown"),
- /// };
- /// });
- /// # }
- /// ```
- #[cfg(feature = "cache")]
- pub fn channel(&self) -> Option<Channel> {
- self.client.as_ref()?.cache.try_borrow().ok()?.channel(self.channel_id)
- }
-
- /// A util function for determining whether this message was sent by someone else, or the
- /// bot.
- #[cfg(all(feature = "cache", feature = "utils"))]
- pub fn is_own(&self) -> Result<bool> {
- let client = self.client.as_ref().ok_or_else(|| {
- Error::Model(ModelError::ClientNotPresent)
- })?;
-
- Ok(self.author.id == client.cache.try_borrow()?.user.id)
- }
-
- /// Deletes the message.
- ///
- /// **Note**: The logged in user must either be the author of the message or
- /// have the [Manage Messages] permission.
- ///
- /// # Errors
- ///
- /// If the `cache` feature is enabled, then returns a
- /// [`ModelError::InvalidPermissions`] if the current user does not have
- /// the required permissions.
- ///
- /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
- /// [`ModelError::InvalidUser`]: enum.ModelError.html#variant.InvalidUser
- /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
- pub fn delete(&self) -> FutureResult<()> {
- let client = ftryopt!(self.client);
-
- #[cfg(feature = "cache")]
- {
- let cache = ftry!(client.cache.try_borrow());
- let req = Permissions::MANAGE_MESSAGES;
- let is_author = self.author.id == cache.user.id;
- let has_perms = ftry!(cache.user_has_perms(self.channel_id, req));
-
- if !is_author && !has_perms {
- return Box::new(future::err(Error::Model(
- ModelError::InvalidPermissions(req),
- )));
- }
- }
-
- client.http.delete_message(self.channel_id.0, self.id.0)
- }
-
- /// Deletes all of the [`Reaction`]s associated with the message.
- ///
- /// **Note**: Requires the [Manage Messages] permission.
- ///
- /// # Errors
- ///
- /// If the `cache` feature is enabled, then returns a
- /// [`ModelError::InvalidPermissions`] if the current user does not have
- /// the required permissions.
- ///
- /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
- /// [`Reaction`]: struct.Reaction.html
- /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
- pub fn delete_reactions(&self) -> FutureResult<()> {
- let client = ftryopt!(self.client);
-
- #[cfg(feature = "cache")]
- {
- let req = Permissions::MANAGE_MESSAGES;
-
- if !ftry!(client.cache.borrow().user_has_perms(self.channel_id, req)) {
- return Box::new(future::err(Error::Model(
- ModelError::InvalidPermissions(req),
- )));
- }
- }
-
- client.http.delete_message_reactions(
- self.channel_id.0,
- self.id.0,
- )
- }
-
- /// Edits this message, replacing the original content with new content.
- ///
- /// 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.
- ///
- /// # Examples
- ///
- /// Edit a message with new content:
- ///
- /// ```rust,ignore
- /// // assuming a `message` has already been bound
- ///
- /// message.edit(|m| m.content("new content"));
- /// ```
- ///
- /// # Errors
- ///
- /// If the `cache` is enabled, returns a [`ModelError::InvalidUser`] if the
- /// current user is not the author.
- ///
- /// Returns a [`ModelError::MessageTooLong`] if the content of the message
- /// is over [`the limit`], containing the number of unicode code points
- /// over the limit.
- ///
- /// [`ModelError::InvalidUser`]: enum.ModelError.html#variant.InvalidUser
- /// [`ModelError::MessageTooLong`]: enum.ModelError.html#variant.MessageTooLong
- /// [`EditMessage`]: ../builder/struct.EditMessage.html
- /// [`the limit`]: ../builder/struct.EditMessage.html#method.content
- pub fn edit<F: FnOnce(EditMessage) -> EditMessage>(&self, f: F)
- -> FutureResult<Message> {
- let client = ftryopt!(self.client);
-
- #[cfg(feature = "cache")]
- {
- if self.author.id != ftry!(client.cache.try_borrow()).user.id {
- return Box::new(future::err(Error::Model(ModelError::InvalidUser)));
- }
- }
-
- ftryopt!(self.client).http.edit_message(self.channel_id.0, self.id.0, f)
- }
-
- pub(crate) fn transform_content(&mut self) {
+ pub fn transform_content(&mut self) {
match self.kind {
MessageType::PinsAdd => {
self.content = format!(
@@ -264,137 +80,6 @@ impl Message {
}
}
- /// Returns message content, but with user and role mentions replaced with
- /// names and everyone/here mentions cancelled.
- #[cfg(feature = "cache")]
- pub fn content_safe(&self) -> String {
- let mut result = self.content.clone();
-
- // First replace all user mentions.
- for u in &self.mentions {
- let mut at_distinct = String::with_capacity(38);
- at_distinct.push('@');
- at_distinct.push_str(&u.name);
- at_distinct.push('#');
- let _ = write!(at_distinct, "{}", u.discriminator);
- result = result.replace(&u.mention(), &at_distinct);
- }
-
- if let Some(guild) = self.guild() {
- if let Some(guild) = guild.try_borrow().ok() {
- // Then replace all role mentions.
- for id in &self.mention_roles {
- let mention = id.mention();
-
- if let Some(role) = guild.roles.get(id).and_then(|r| r.try_borrow().ok()) {
- result = result.replace(
- &mention,
- &format!("@{}", role.name),
- );
- } else {
- result = result.replace(&mention, "@deleted-role");
- }
- }
- }
- }
-
- // And finally replace everyone and here mentions.
- result
- .replace("@everyone", "@\u{200B}everyone")
- .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 reaction_users<R, U>(
- &self,
- reaction_type: R,
- limit: Option<u8>,
- after: U,
- ) -> FutureResult<Vec<User>>
- where R: Into<ReactionType>, U: Into<Option<UserId>> {
- ftryopt!(self.client).http.get_reaction_users(
- self.channel_id.0,
- self.id.0,
- &reaction_type.into(),
- limit,
- after.into().map(|x| x.0),
- )
- }
-
- /// Returns the associated `Guild` for the message if one is in the cache.
- ///
- /// Returns `None` if the guild's Id could not be found via [`guild_id`] or
- /// if the Guild itself is not cached.
- ///
- /// Requires the `cache` feature be enabled.
- ///
- /// [`guild_id`]: #method.guild_id
- #[cfg(feature = "cache")]
- pub fn guild(&self) -> Option<Rc<RefCell<Guild>>> {
- self.guild_id().and_then(|guild_id| {
- self.client.as_ref()?.cache.try_borrow().ok()?.guild(guild_id)
- })
- }
-
- /// 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(feature = "cache")]
- pub fn guild_id(&self) -> Option<GuildId> {
- match self.client.as_ref()?.cache.try_borrow().ok()?.channel(self.channel_id) {
- Some(Channel::Guild(ch)) => Some(ch.borrow().guild_id),
- _ => None,
- }
- }
-
- /// True if message was sent using direct messages.
- ///
- /// Returns `false` if a client is not present on the model.
- #[cfg(feature = "cache")]
- pub fn is_private(&self) -> bool {
- self.client.as_ref().map(|client| {
- let cache = client.cache.borrow();
-
- match cache.channel(self.channel_id) {
- Some(Channel::Group(_)) | Some(Channel::Private(_)) => true,
- _ => false,
- }
- }).unwrap_or(false)
- }
-
- /// Retrieves a clone of the author's Member instance, if this message was
- /// sent in a guild.
- ///
- /// Note that since this clones, it is preferable performance-wise to
- /// manually retrieve the guild from the cache and access
- /// [`Guild::members`].
- ///
- /// [`Guild::members`]: ../guild/struct.Guild.html#structfield.members
- #[cfg(feature = "cache")]
- pub fn member(&self) -> Option<Rc<RefCell<Member>>> {
- self.guild().and_then(|guild| {
- guild.try_borrow().ok()?.members.get(&self.author.id).cloned()
- })
- }
-
/// Checks the length of a string to ensure that it is within Discord's
/// maximum message length limit.
///
@@ -414,155 +99,7 @@ impl Message {
}
}
- /// Pins this message to its channel.
- ///
- /// **Note**: Requires the [Manage Messages] permission.
- ///
- /// # Errors
- ///
- /// If the `cache` is enabled, returns a
- /// [`ModelError::InvalidPermissions`] if the current user does not have
- /// the required permissions.
- ///
- /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
- /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
- pub fn pin(&self) -> FutureResult<()> {
- let client = ftryopt!(self.client);
-
- #[cfg(feature = "cache")]
- {
- let req = Permissions::MANAGE_MESSAGES;
-
- if !ftry!(client.cache.borrow().user_has_perms(self.channel_id, req)) {
- return Box::new(future::err(Error::Model(
- ModelError::InvalidPermissions(req),
- )));
- }
- }
-
- client.http.pin_message(self.channel_id.0, self.id.0)
- }
-
- /// React to the message with a custom [`Emoji`] or unicode character.
- ///
- /// **Note**: Requires the [Add Reactions] permission.
- ///
- /// # Errors
- ///
- /// If the `cache` is enabled, returns a
- /// [`ModelError::InvalidPermissions`] if the current user does not have the
- /// required [permissions].
- ///
- /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
- /// [`Emoji`]: struct.Emoji.html
- /// [Add Reactions]: permissions/constant.ADD_REACTIONS.html
- /// [permissions]: permissions
- pub fn react<R: Into<ReactionType>>(&self, reaction_type: R)
- -> FutureResult<()> {
- let client = ftryopt!(self.client);
-
- #[cfg(feature = "cache")]
- {
- let req = Permissions::ADD_REACTIONS;
-
- if !ftry!(client.cache.borrow().user_has_perms(self.channel_id, req)) {
- return Box::new(future::err(Error::Model(
- ModelError::InvalidPermissions(req),
- )));
- }
- }
-
- client.http.create_reaction(
- self.channel_id.0,
- self.id.0,
- &reaction_type.into(),
- )
- }
-
- /// Replies to the user, mentioning them prior to the content in the form
- /// of: `@<USER_ID>: YOUR_CONTENT`.
- ///
- /// User mentions are generally around 20 or 21 characters long.
- ///
- /// **Note**: Requires the [Send Messages] permission.
- ///
- /// **Note**: Message contents must be under 2000 unicode code points.
- ///
- /// # Errors
- ///
- /// If the `cache` is enabled, returns a
- /// [`ModelError::InvalidPermissions`] if the current user does not have
- /// the required permissions.
- ///
- /// 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.
- ///
- /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
- /// [`ModelError::MessageTooLong`]: enum.ModelError.html#variant.MessageTooLong
- /// [Send Messages]: permissions/constant.SEND_MESSAGES.html
- pub fn reply(&self, content: &str) -> FutureResult<Message> {
- if let Some(length_over) = Message::overflow_length(content) {
- return Box::new(future::err(Error::Model(
- ModelError::MessageTooLong(length_over),
- )));
- }
-
- let client = ftryopt!(self.client);
-
- #[cfg(feature = "cache")]
- {
- let req = Permissions::SEND_MESSAGES;
-
- if !ftry!(client.cache.borrow().user_has_perms(self.channel_id, req)) {
- return Box::new(future::err(Error::Model(
- ModelError::InvalidPermissions(req),
- )));
- }
- }
-
- let mut gen = self.author.mention();
- gen.push_str(": ");
- gen.push_str(content);
-
- let done = client.http.send_message(
- self.channel_id.0,
- |f| f.content(gen).tts(false),
- );
-
- Box::new(done)
- }
-
- /// Unpins the message from its channel.
- ///
- /// **Note**: Requires the [Manage Messages] permission.
- ///
- /// # Errors
- ///
- /// If the `cache` is enabled, returns a
- /// [`ModelError::InvalidPermissions`] if the current user does not have
- /// the required permissions.
- ///
- /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
- /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
- pub fn unpin(&self) -> FutureResult<()> {
- let client = ftryopt!(self.client);
-
- #[cfg(feature = "cache")]
- {
- let req = Permissions::MANAGE_MESSAGES;
-
- if !ftry!(client.cache.borrow().user_has_perms(self.channel_id, req)) {
- return Box::new(future::err(Error::Model(
- ModelError::InvalidPermissions(req),
- )));
- }
- }
-
- client.http.unpin_message(self.channel_id.0, self.id.0)
- }
-
- pub(crate) fn check_content_length(map: &JsonMap) -> Result<()> {
+ pub fn check_content_length(map: &JsonMap) -> Result<()> {
if let Some(content) = map.get("content") {
if let Value::String(ref content) = *content {
if let Some(length_over) = Message::overflow_length(content) {
@@ -574,7 +111,7 @@ impl Message {
Ok(())
}
- pub(crate) fn check_embed_length(map: &JsonMap) -> Result<()> {
+ pub fn check_embed_length(map: &JsonMap) -> Result<()> {
let embed = match map.get("embed") {
Some(&Value::Object(ref value)) => value,
_ => return Ok(()),
diff --git a/src/model/channel/mod.rs b/src/model/channel/mod.rs
index 9177064..a527173 100644
--- a/src/model/channel/mod.rs
+++ b/src/model/channel/mod.rs
@@ -20,20 +20,14 @@ pub use self::private_channel::*;
pub use self::reaction::*;
pub use self::channel_category::*;
-use futures::Future;
use model::prelude::*;
use serde::de::Error as DeError;
use serde::ser::{SerializeStruct, Serialize, Serializer};
use serde_json;
use std::cell::RefCell;
+use std::fmt::{Display, Formatter, Result as FmtResult};
use std::rc::Rc;
use super::utils::deserialize_u64;
-use ::FutureResult;
-
-#[cfg(feature = "model")]
-use builder::{CreateMessage, EditMessage};
-#[cfg(feature = "model")]
-use std::fmt::{Display, Formatter, Result as FmtResult};
/// A container for any channel.
#[derive(Clone, Debug)]
@@ -181,131 +175,6 @@ impl Channel {
}
}
- /// 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
- #[cfg(feature = "model")]
- #[deprecated(since = "0.4.2", note = "Use the inner channel's method")]
- #[inline]
- pub fn create_reaction<M, R>(&self, message_id: M, reaction_type: R)
- -> FutureResult<()> where M: Into<MessageId>, R: Into<ReactionType> {
- ftryopt!(ftry!(self.client())).http.create_reaction(
- self.id().0,
- message_id.into().0,
- &reaction_type.into(),
- )
- }
-
- /// Deletes the inner channel.
- ///
- /// **Note**: There is no real function as _deleting_ a [`Group`]. The
- /// closest functionality is leaving it.
- ///
- /// [`Group`]: struct.Group.html
- #[cfg(feature = "model")]
- pub fn delete(&self) -> FutureResult<()> {
- match *self {
- Channel::Group(ref group) => {
- Box::new(group.borrow().leave())
- },
- Channel::Guild(ref public_channel) => {
- Box::new(public_channel.borrow().delete().map(|_| ()))
- },
- Channel::Private(ref private_channel) => {
- Box::new(private_channel.borrow().delete().map(|_| ()))
- },
- Channel::Category(ref category) => {
- Box::new(category.borrow().delete())
- },
- }
- }
-
- /// 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
- #[cfg(feature = "model")]
- #[deprecated(since = "0.4.2", note = "Use the inner channel's method")]
- #[inline]
- pub fn delete_message<M>(&self, message_id: M) -> FutureResult<()>
- where M: Into<MessageId> {
- ftryopt!(ftry!(self.client())).http.delete_message(
- self.id().0,
- message_id.into().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
- #[cfg(feature = "model")]
- #[deprecated(since = "0.4.2", note = "Use the inner channel's method")]
- #[inline]
- pub fn delete_reaction<M, R>(
- &self,
- message_id: M,
- user_id: Option<UserId>,
- reaction_type: R,
- ) -> FutureResult<()> where M: Into<MessageId>, R: Into<ReactionType> {
- ftryopt!(ftry!(self.client())).http.delete_reaction(
- self.id().0,
- message_id.into().0,
- user_id.map(|x| x.0),
- &reaction_type.into(),
- )
- }
-
- /// 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
- #[cfg(feature = "model")]
- #[deprecated(since = "0.4.2", note = "Use the inner channel's method")]
- #[inline]
- pub fn edit_message<F, M>(&self, message_id: M, f: F)
- -> FutureResult<Message>
- where F: FnOnce(EditMessage) -> EditMessage, M: Into<MessageId> {
- ftryopt!(ftry!(self.client())).http.edit_message(
- self.id().0,
- message_id.into().0,
- f,
- )
- }
-
/// Determines if the channel is NSFW.
///
/// Refer to [`utils::is_nsfw`] for more details.
@@ -321,57 +190,6 @@ impl Channel {
}
}
- /// Gets a message from the channel.
- ///
- /// Requires the [Read Message History] permission.
- ///
- /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
- #[cfg(feature = "model")]
- #[deprecated(since = "0.4.2", note = "Use the inner channel's method")]
- #[inline]
- pub fn message<M>(&self, message_id: M) -> FutureResult<Message>
- where M: Into<MessageId> {
- ftryopt!(ftry!(self.client())).http.get_message(
- self.id().0,
- message_id.into().0,
- )
- }
-
- /// 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
- #[cfg(feature = "model")]
- #[deprecated(since = "0.4.2", note = "Use the inner channel's method")]
- #[inline]
- pub fn reaction_users<M, R, U>(&self,
- message_id: M,
- reaction_type: R,
- limit: Option<u8>,
- after: U,
- ) -> FutureResult<Vec<User>>
- where M: Into<MessageId>, R: Into<ReactionType>, U: Into<Option<UserId>> {
- ftryopt!(ftry!(self.client())).http.get_reaction_users(
- self.id().0,
- message_id.into().0,
- &reaction_type.into(),
- limit,
- after.into().map(|x| x.0),
- )
- }
-
/// Retrieves the Id of the inner [`Group`], [`GuildChannel`], or
/// [`PrivateChannel`].
///
@@ -386,106 +204,6 @@ impl Channel {
Channel::Category(ref category) => category.borrow().id,
}
}
-
- /// 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`]: struct.ChannelId.html
- /// [`ModelError::MessageTooLong`]: enum.ModelError.html#variant.MessageTooLong
- #[cfg(feature = "model")]
- #[deprecated(since = "0.4.2", note = "Use the inner channel's method")]
- #[inline]
- pub fn say(&self, content: &str) -> FutureResult<Message> {
- ftryopt!(ftry!(self.client())).http.send_message(self.id().0, |f|
- f.content(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
- // todo
- // #[cfg(feature = "model")]
- // #[deprecated(since = "0.4.2", note = "Use the inner channel's method")]
- // #[inline]
- // pub fn send_files<'a, F, T, It>(&self, files: It, f: F)
- // -> FutureResult<Message>
- // where F: FnOnce(CreateMessage) -> CreateMessage,
- // T: Into<AttachmentType<'a>>,
- // It: IntoIterator<Item = T> {
- // ftryopt!(ftry!(self.client())).http.send_files(self.id(), files, 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 [`ModelError::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
- /// [`ModelError::MessageTooLong`]: enum.ModelError.html#variant.MessageTooLong
- /// [`CreateMessage`]: ../builder/struct.CreateMessage.html
- /// [Send Messages]: permissions/constant.SEND_MESSAGES.html
- #[cfg(feature = "model")]
- #[deprecated(since = "0.4.2", note = "Use the inner channel's method")]
- #[inline]
- pub fn send_message<F>(&self, f: F) -> FutureResult<Message>
- where F: FnOnce(CreateMessage) -> CreateMessage {
- ftryopt!(ftry!(self.client())).http.send_message(self.id().0, 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
- #[cfg(feature = "model")]
- #[deprecated(since = "0.4.2", note = "Use the inner channel's method")]
- #[inline]
- pub fn unpin<M: Into<MessageId>>(&self, message_id: M) -> FutureResult<()> {
- let retrieve = ftry!(self.client());
- let obtained = ftryopt!(retrieve);
-
- obtained.http.unpin_message(self.id().0, message_id.into().0)
- }
-
- fn client(&self) -> Result<WrappedClient> {
- Ok(match *self {
- Channel::Category(ref c) => c.try_borrow()?.client.as_ref().map(Rc::clone),
- Channel::Group(ref c) => c.try_borrow()?.client.as_ref().map(Rc::clone),
- Channel::Guild(ref c) => c.try_borrow()?.client.as_ref().map(Rc::clone),
- Channel::Private(ref c) => c.try_borrow()?.client.as_ref().map(Rc::clone),
- })
- }
}
impl<'de> Deserialize<'de> for Channel {
@@ -535,7 +253,6 @@ impl Serialize for Channel {
}
}
-#[cfg(feature = "model")]
impl Display for Channel {
/// Formats the channel into a "mentioned" string.
///
diff --git a/src/model/channel/private_channel.rs b/src/model/channel/private_channel.rs
index 48d887b..74f6785 100644
--- a/src/model/channel/private_channel.rs
+++ b/src/model/channel/private_channel.rs
@@ -1,15 +1,9 @@
use chrono::{DateTime, FixedOffset};
-use futures::Future;
use model::prelude::*;
use std::cell::RefCell;
use std::fmt::{Display, Formatter, Result as FmtResult};
use std::rc::Rc;
-use super::super::WrappedClient;
use super::deserialize_single_recipient;
-use ::FutureResult;
-
-#[cfg(feature = "model")]
-use builder::{CreateMessage, EditMessage, GetMessages};
/// A Direct Message text channel with another user.
#[derive(Clone, Debug, Deserialize, Serialize)]
@@ -36,302 +30,13 @@ pub struct PrivateChannel {
rename = "recipients",
serialize_with = "serialize_user")]
pub recipient: Rc<RefCell<User>>,
- #[serde(skip)]
- pub(crate) client: WrappedClient,
}
-#[cfg(feature = "model")]
impl PrivateChannel {
- /// Broadcasts that the current user is typing to the recipient.
- pub fn broadcast_typing(&self) -> FutureResult<()> {
- ftryopt!(self.client).http.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)
- -> FutureResult<()> where M: Into<MessageId>, R: Into<ReactionType> {
- ftryopt!(self.client).http.create_reaction(
- self.id.0,
- message_id.into().0,
- &reaction_type.into(),
- )
- }
-
- /// 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.
- #[inline]
- pub fn delete(&self) -> FutureResult<Channel> {
- ftryopt!(self.client).http.delete_channel(self.id.0)
- }
-
- /// 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<T: AsRef<MessageId>, It: IntoIterator<Item=T>>(
- &self,
- message_ids: It,
- ) -> FutureResult<()> {
- ftryopt!(self.client).http.delete_messages(self.id.0, 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)
- -> FutureResult<()> {
- let overwrite_id = match permission_type {
- PermissionOverwriteType::Member(id) => id.0,
- PermissionOverwriteType::Role(id) => id.0,
- };
-
- ftryopt!(self.client).http.delete_permission(self.id.0, overwrite_id)
- }
-
- /// 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: Into<MessageId>, R: Into<ReactionType>>(
- &self,
- message_id: M,
- user_id: Option<UserId>,
- reaction_type: R,
- ) -> FutureResult<()> {
- ftryopt!(self.client).http.delete_reaction(
- self.id.0,
- message_id.into().0,
- user_id.map(|x| x.0),
- &reaction_type.into(),
- )
- }
-
- /// 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<F, M>(&self, message_id: M, f: F)
- -> FutureResult<Message>
- where F: FnOnce(EditMessage) -> EditMessage, M: Into<MessageId> {
- ftryopt!(self.client).http.edit_message(
- self.id.0,
- message_id.into().0,
- f,
- )
- }
-
- /// 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 DMs not being considered NSFW.
- ///
- /// [`utils::is_nsfw`]: ../utils/fn.is_nsfw.html
- #[inline]
- pub fn is_nsfw(&self) -> bool { false }
-
- /// 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<M: Into<MessageId>>(&self, message_id: M)
- -> FutureResult<Message> {
- ftryopt!(self.client).http.get_message(self.id.0, message_id.into().0)
- }
-
- /// Gets messages from the channel.
- ///
- /// Refer to [`Channel::messages`] for more information.
- ///
- /// Requires the [Read Message History] permission.
- ///
- /// [`Channel::messages`]: enum.Channel.html#method.messages
- /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
- #[inline]
- pub fn messages<'a, F: FnOnce(GetMessages) -> GetMessages>(&'a self, f: F)
- -> Box<Future<Item = Vec<Message>, Error = Error> + 'a> {
- ftryopt!(self.client).http.get_messages(self.id.0, f)
- }
-
/// Returns "DM with $username#discriminator".
pub fn name(&self) -> String {
format!("DM with {}", self.recipient.borrow().tag())
}
-
- /// 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<M, R, U>(
- &self,
- message_id: M,
- reaction_type: R,
- limit: Option<u8>,
- after: U,
- ) -> FutureResult<Vec<User>>
- where M: Into<MessageId>, R: Into<ReactionType>, U: Into<Option<UserId>> {
- ftryopt!(self.client).http.get_reaction_users(
- self.id.0,
- message_id.into().0,
- &reaction_type.into(),
- limit,
- after.into().map(|x| x.0),
- )
- }
-
- /// Pins a [`Message`] to the channel.
- ///
- /// [`Message`]: struct.Message.html
- #[inline]
- pub fn pin<M: Into<MessageId>>(&self, message_id: M) -> FutureResult<()> {
- ftryopt!(self.client).http.pin_message(self.id.0, message_id.into().0)
- }
-
- /// Retrieves the list of messages that have been pinned in the private
- /// channel.
- #[inline]
- pub fn pins(&self) -> FutureResult<Vec<Message>> {
- ftryopt!(self.client).http.get_pins(self.id.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<D: ::std::fmt::Display>(&self, content: D)
- -> FutureResult<Message> {
- ftryopt!(self.client)
- .http
- .send_message(self.id.0, |m| m.content(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
- // todo
- // #[inline]
- // pub fn send_files<'a, F, T, It>(&self, files: It, f: F)
- // -> FutureResult<Message>
- // where F: FnOnce(CreateMessage) -> CreateMessage,
- // T: Into<AttachmentType<'a>>,
- // It: IntoIterator<Item=T> {
- // ftryopt!(self.client).http.send_files(self.id.0, files, f)
- // }
-
- /// Sends a message to the channel with the given content.
- ///
- /// Refer to the documentation for [`CreateMessage`] for more information
- /// regarding message restrictions and requirements.
- ///
- /// # 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.
- ///
- /// [`ModelError::MessageTooLong`]: enum.ModelError.html#variant.MessageTooLong
- /// [`CreateMessage`]: ../builder/struct.CreateMessage.html
- /// [`Message`]: struct.Message.html
- #[inline]
- pub fn send_message<F: FnOnce(CreateMessage) -> CreateMessage>(&self, f: F)
- -> FutureResult<Message> {
- ftryopt!(self.client).http.send_message(self.id.0, 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) -> FutureResult<()> {
- ftryopt!(self.client).http.unpin_message(self.id.0, message_id.into().0)
- }
}
impl Display for PrivateChannel {
diff --git a/src/model/channel/reaction.rs b/src/model/channel/reaction.rs
index 28ddb8d..1111a55 100644
--- a/src/model/channel/reaction.rs
+++ b/src/model/channel/reaction.rs
@@ -1,12 +1,9 @@
-use futures::future;
use model::prelude::*;
use serde::de::{Deserialize, Error as DeError, MapAccess, Visitor};
use serde::ser::{SerializeMap, Serialize, Serializer};
use std::error::Error as StdError;
use std::fmt::{Display, Formatter, Result as FmtResult, Write as FmtWrite};
use std::str::FromStr;
-use super::super::WrappedClient;
-use ::FutureResult;
use internal::prelude::*;
/// An emoji reaction to a message.
@@ -27,150 +24,6 @@ pub struct Reaction {
///
/// [`User`]: struct.User.html
pub user_id: UserId,
- #[serde(skip)]
- pub(crate) client: WrappedClient,
-}
-
-#[cfg(feature = "model")]
-impl Reaction {
- /// Retrieves the associated the reaction was made in.
- ///
- /// If the cache is enabled, this will search for the already-cached
- /// channel. If not - or the channel was not found - this will perform a
- /// request over the REST API for the channel.
- ///
- /// Requires the [Read Message History] permission.
- ///
- /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
- #[inline]
- pub fn channel(&self) -> FutureResult<Channel> {
- ftryopt!(self.client).http.get_channel(self.channel_id.0)
- }
-
- /// Deletes the reaction, but only if the current user is the user who made
- /// the reaction or has permission to.
- ///
- /// Requires the [Manage Messages] permission, _if_ the current
- /// user did not perform the reaction.
- ///
- /// # Errors
- ///
- /// If the `cache` is enabled, then returns a
- /// [`ModelError::InvalidPermissions`] if the current user does not have
- /// the required [permissions].
- ///
- /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
- /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
- /// [permissions]: permissions
- pub fn delete(&self) -> FutureResult<()> {
- let client = ftryopt!(self.client);
-
- let user_id = feature_cache! {{
- let cache = ftry!(client.cache.try_borrow());
-
- let user = if self.user_id == cache.user.id {
- None
- } else {
- Some(self.user_id.0)
- };
-
- // If the reaction is one _not_ made by the current user, then ensure
- // that the current user has permission* to delete the reaction.
- //
- // Normally, users can only delete their own reactions.
- //
- // * The `Manage Messages` permission.
- if user.is_some() {
- let req = Permissions::MANAGE_MESSAGES;
-
- if !cache.user_has_perms(self.channel_id, req).unwrap_or(true) {
- return Box::new(future::err(Error::Model(
- ModelError::InvalidPermissions(req),
- )));
- }
- }
-
- user
- } else {
- Some(self.user_id.0)
- }};
-
- ftryopt!(self.client).http.delete_reaction(
- self.channel_id.0,
- self.message_id.0,
- user_id,
- &self.emoji,
- )
- }
-
- /// Retrieves the [`Message`] associated with this reaction.
- ///
- /// Requires the [Read Message History] permission.
- ///
- /// **Note**: This will send a request to the REST API. Prefer maintaining
- /// your own message cache or otherwise having the message available if
- /// possible.
- ///
- /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
- /// [`Message`]: struct.Message.html
- #[inline]
- pub fn message(&self) -> FutureResult<Message> {
- ftryopt!(self.client).http.get_message(
- self.channel_id.0,
- self.message_id.0,
- )
- }
-
- /// Retrieves the user that made the reaction.
- ///
- /// If the cache is enabled, this will search for the already-cached user.
- /// If not - or the user was not found - this will perform a request over
- /// the REST API for the user.
- #[inline]
- pub fn user(&self) -> FutureResult<User> {
- ftryopt!(self.client).http.get_user(self.user_id.0)
- }
-
- /// Retrieves 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.
- ///
- /// Requires the [Read Message History] permission.
- ///
- /// **Note**: This will send a request to the REST API.
- ///
- /// # Errors
- ///
- /// Returns a [`ModelError::InvalidPermissions`] if the current user does
- /// not have the required [permissions].
- ///
- /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
- /// [`Emoji`]: struct.Emoji.html
- /// [`Message`]: struct.Message.html
- /// [`User`]: struct.User.html
- /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
- /// [permissions]: permissions
- pub fn users<R, U>(
- &self,
- reaction_type: R,
- limit: Option<u8>,
- after: Option<U>,
- ) -> FutureResult<Vec<User>>
- where R: Into<ReactionType>, U: Into<UserId> {
- ftryopt!(self.client).http.get_reaction_users(
- self.channel_id.0,
- self.message_id.0,
- &reaction_type.into(),
- limit,
- after.map(|u| u.into().0),
- )
- }
}
/// The type of a [`Reaction`] sent.
@@ -313,7 +166,6 @@ impl ReactionType {
}
}
-#[cfg(feature = "model")]
impl From<char> for ReactionType {
/// Creates a `ReactionType` from a `char`.
///
diff --git a/src/model/gateway.rs b/src/model/gateway.rs
index ad30bab..b5fa84b 100644
--- a/src/model/gateway.rs
+++ b/src/model/gateway.rs
@@ -39,7 +39,6 @@ pub struct Game {
pub url: Option<String>,
}
-#[cfg(feature = "model")]
impl Game {
/// Creates a `Game` struct that appears as a `Playing <name>` status.
///
diff --git a/src/model/guild/emoji.rs b/src/model/guild/emoji.rs
index 48d9b7d..08f63ef 100644
--- a/src/model/guild/emoji.rs
+++ b/src/model/guild/emoji.rs
@@ -1,17 +1,5 @@
use std::fmt::{Display, Formatter, Result as FmtResult, Write as FmtWrite};
use super::super::id::{EmojiId, RoleId};
-use super::super::WrappedClient;
-
-#[cfg(feature = "cache")]
-use futures::{Future, future};
-#[cfg(all(feature = "cache", feature = "model"))]
-use internal::prelude::*;
-#[cfg(all(feature = "cache", feature = "model"))]
-use super::super::ModelError;
-#[cfg(all(feature = "cache", feature = "model"))]
-use super::super::id::GuildId;
-#[cfg(feature = "cache")]
-use ::FutureResult;
/// Represents a custom guild emoji, which can either be created using the API,
/// or via an integration. Emojis created using the API only work within the
@@ -38,136 +26,9 @@ pub struct Emoji {
///
/// [`Role`]: struct.Role.html
pub roles: Vec<RoleId>,
- #[serde(skip)]
- pub(crate) client: WrappedClient,
}
-#[cfg(feature = "model")]
impl Emoji {
- /// Deletes the emoji.
- ///
- /// **Note**: The [Manage Emojis] permission is required.
- ///
- /// **Note**: Only user accounts may use this method.
- ///
- /// [Manage Emojis]: permissions/constant.MANAGE_EMOJIS.html
- ///
- /// # Examples
- ///
- /// Delete a given emoji:
- ///
- /// ```rust,no_run
- /// # use serenity::model::guild::Emoji;
- /// # use serenity::model::id::EmojiId;
- /// #
- /// # let mut emoji = Emoji {
- /// # animated: false,
- /// # id: EmojiId(7),
- /// # name: String::from("blobface"),
- /// # managed: false,
- /// # require_colons: false,
- /// # roles: vec![],
- /// # };
- /// #
- /// // assuming emoji has been set already
- /// match emoji.delete() {
- /// Ok(()) => println!("Emoji deleted."),
- /// Err(_) => println!("Could not delete emoji.")
- /// }
- /// ```
- #[cfg(feature = "cache")]
- pub fn delete(&self) -> FutureResult<()> {
- let guild_id = match self.find_guild_id() {
- Some(guild_id) => guild_id,
- None => return Box::new(future::err(Error::Model(
- ModelError::ItemMissing,
- ))),
- };
-
- ftryopt!(self.client).http.delete_emoji(guild_id.0, self.id.0)
- }
-
- /// Edits the emoji by updating it with a new name.
- ///
- /// **Note**: The [Manage Emojis] permission is required.
- ///
- /// **Note**: Only user accounts may use this method.
- ///
- /// [Manage Emojis]: permissions/constant.MANAGE_EMOJIS.html
- ///
- /// # Examples
- ///
- /// Change the name of an emoji:
- ///
- /// ```rust,no_run
- /// # use serenity::model::guild::Emoji;
- /// # use serenity::model::id::EmojiId;
- /// #
- /// # let mut emoji = Emoji {
- /// # animated: false,
- /// # id: EmojiId(7),
- /// # name: String::from("blobface"),
- /// # managed: false,
- /// # require_colons: false,
- /// # roles: vec![],
- /// # };
- /// #
- /// // assuming emoji has been set already
- /// let _ = emoji.edit("blobuwu");
- /// assert_eq!(emoji.name, "blobuwu");
- /// ```
- #[cfg(feature = "cache")]
- pub fn edit<'a>(&'a mut self, name: &'a str)
- -> Box<Future<Item = Emoji, Error = Error> + 'a> {
- let guild_id = match self.find_guild_id() {
- Some(guild_id) => guild_id,
- None => return Box::new(future::err(Error::Model(
- ModelError::ItemMissing,
- ))),
- };
-
- ftryopt!(self.client).http.edit_emoji(guild_id.0, self.id.0, name)
- }
-
- /// Finds the [`Guild`] that owns the emoji by looking through the Cache.
- ///
- /// [`Guild`]: struct.Guild.html
- ///
- /// # Examples
- ///
- /// Print the guild id that owns this emoji:
- ///
- /// ```rust,no_run
- /// # use serenity::model::guild::Emoji;
- /// # use serenity::model::id::EmojiId;
- /// #
- /// # let mut emoji = Emoji {
- /// # animated: false,
- /// # id: EmojiId(7),
- /// # name: String::from("blobface"),
- /// # managed: false,
- /// # require_colons: false,
- /// # roles: vec![],
- /// # };
- /// #
- /// // assuming emoji has been set already
- /// if let Some(guild_id) = emoji.find_guild_id() {
- /// println!("{} is owned by {}", emoji.name, guild_id);
- /// }
- /// ```
- #[cfg(feature = "cache")]
- pub fn find_guild_id(&self) -> Option<GuildId> {
- for guild in self.client.as_ref()?.cache.borrow().guilds.values() {
- let guild = guild.borrow();
-
- if guild.emojis.contains_key(&self.id) {
- return Some(guild.id);
- }
- }
-
- None
- }
-
/// Generates a URL to the emoji's image.
///
/// # Examples
diff --git a/src/model/guild/guild_id.rs b/src/model/guild/guild_id.rs
index ea095a0..eacf07e 100644
--- a/src/model/guild/guild_id.rs
+++ b/src/model/guild/guild_id.rs
@@ -1,6 +1,5 @@
use model::prelude::*;
-#[cfg(feature = "model")]
impl GuildId {
/// Converts the guild Id into the default channel's Id.
#[inline]
diff --git a/src/model/guild/member.rs b/src/model/guild/member.rs
index 0c22597..bc8e27e 100644
--- a/src/model/guild/member.rs
+++ b/src/model/guild/member.rs
@@ -1,19 +1,8 @@
use chrono::{DateTime, FixedOffset};
-use futures::future;
use model::prelude::*;
+use std::borrow::Cow;
use std::cell::RefCell;
-use super::super::WrappedClient;
use super::deserialize_user;
-use ::FutureResult;
-
-#[cfg(all(feature = "builder", feature = "cache", feature = "model"))]
-use builder::EditMember;
-#[cfg(all(feature = "cache", feature = "model"))]
-use internal::prelude::*;
-#[cfg(feature = "model")]
-use std::borrow::Cow;
-#[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
-use utils::Colour;
/// A trait for allowing both u8 or &str or (u8, &str) to be passed into the `ban` methods in `Guild` and `Member`.
pub trait BanOptions {
@@ -70,132 +59,9 @@ pub struct Member {
#[serde(deserialize_with = "deserialize_user",
serialize_with = "serialize_user")]
pub user: Rc<RefCell<User>>,
- #[serde(skip)]
- pub(crate) client: WrappedClient,
}
-#[cfg(feature = "model")]
impl Member {
- /// Adds a [`Role`] to the member.
- ///
- /// **Note**: Requires the [Manage Roles] permission.
- ///
- /// [`Role`]: struct.Role.html
- /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
- #[cfg(feature = "cache")]
- pub fn add_role<R: Into<RoleId>>(&mut self, role_id: R)
- -> FutureResult<()> {
- let role_id = role_id.into();
-
- if self.roles.contains(&role_id) {
- return Box::new(future::ok(()));
- }
-
- ftryopt!(self.client).http.add_member_role(
- self.guild_id.0,
- self.user.borrow().id.0,
- role_id.0,
- )
- }
-
- /// Adds one or multiple [`Role`]s to the member.
- ///
- /// **Note**: Requires the [Manage Roles] permission.
- ///
- /// [`Role`]: struct.Role.html
- /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
- #[cfg(feature = "cache")]
- pub fn add_roles(&mut self, role_ids: &[RoleId]) -> FutureResult<()> {
- let mut roles = self.roles.clone();
- roles.extend(role_ids);
-
- ftryopt!(self.client).http.edit_member(
- self.guild_id.0,
- self.user.borrow().id.0,
- |f| f.roles(roles),
- )
- }
-
- /// Ban the member from its guild, deleting the last X number of
- /// days' worth of messages.
- ///
- /// **Note**: Requires the [Ban Members] permission.
- ///
- /// # Errors
- ///
- /// Returns a [`ModelError::GuildNotFound`] if the guild could not be
- /// found.
- ///
- /// [`ModelError::GuildNotFound`]: enum.ModelError.html#variant.GuildNotFound
- ///
- /// [Ban Members]: permissions/constant.BAN_MEMBERS.html
- #[cfg(feature = "cache")]
- pub fn ban<BO: BanOptions>(&self, ban_options: &BO) -> FutureResult<()> {
- let dmd = ban_options.dmd();
-
- if dmd > 7 {
- return Box::new(future::err(Error::Model(
- ModelError::DeleteMessageDaysAmount(dmd),
- )));
- }
-
- let reason = ban_options.reason();
-
- if reason.len() > 512 {
- return Box::new(future::err(Error::ExceededLimit(
- reason.to_string(),
- 512,
- )));
- }
-
- ftryopt!(self.client).http.ban_user(
- self.guild_id.0,
- self.user.borrow().id.0,
- dmd,
- &*reason,
- )
- }
-
- /// Determines the member's colour.
- #[cfg(all(feature = "cache", feature = "utils"))]
- pub fn colour(&self) -> Option<Colour> {
- let client = self.client.as_ref()?;
- let cache = client.cache.try_borrow().ok()?;
- let guild = cache.guild(self.guild_id)?;
- let guild = guild.borrow();
-
- let mut roles = self.roles
- .iter()
- .filter_map(|role_id| guild.roles.get(role_id))
- .collect::<Vec<&Rc<RefCell<Role>>>>();
- roles.sort_by(|a, b| b.cmp(a));
-
- let default = Colour::default();
-
- roles
- .iter()
- .find(|r| r.borrow().colour.0 != default.0)
- .map(|r| r.borrow().colour)
- }
-
- /// Returns the "default channel" of the guild for the member.
- /// (This returns the first channel that can be read by the member, if there isn't
- /// one returns `None`)
- #[cfg(feature = "cache")]
- pub fn default_channel(&self) -> Option<Rc<RefCell<GuildChannel>>> {
- let cache = self.client.as_ref()?.cache.borrow();
- let guild = cache.guild(self.guild_id)?;
- let reader = guild.borrow();
-
- for (cid, channel) in &reader.channels {
- if reader.permissions_in(*cid, self.user.borrow().id).read_messages() {
- return Some(Rc::clone(channel));
- }
- }
-
- None
- }
-
/// Calculates the member's display name.
///
/// The nickname takes priority over the member's username if it exists.
@@ -222,252 +88,4 @@ impl Member {
)
}
}
-
- /// Edits the member with the given data. See [`Guild::edit_member`] for
- /// more information.
- ///
- /// See [`EditMember`] for the permission(s) required for separate builder
- /// methods, as well as usage of this.
- ///
- /// [`Guild::edit_member`]: ../model/guild/struct.Guild.html#method.edit_member
- /// [`EditMember`]: ../builder/struct.EditMember.html
- #[cfg(feature = "cache")]
- pub fn edit<F: FnOnce(EditMember) -> EditMember>(&self, f: F)
- -> FutureResult<()> {
- ftryopt!(self.client).http.edit_member(
- self.guild_id.0,
- self.user.borrow().id.0,
- f,
- )
- }
-
- /// Retrieves the ID and position of the member's highest role in the
- /// hierarchy, if they have one.
- ///
- /// This _may_ return `None` if the user has roles, but they are not present
- /// in the cache for cache inconsistency reasons.
- ///
- /// The "highest role in hierarchy" is defined as the role with the highest
- /// position. If two or more roles have the same highest position, then the
- /// role with the lowest ID is the highest.
- ///
- /// # Deadlocking
- ///
- /// This function will deadlock if you have a write lock to the member's
- /// guild.
- #[cfg(feature = "cache")]
- pub fn highest_role_info(&self) -> Option<(RoleId, i64)> {
- let cache = self.client.as_ref()?.cache.try_borrow().ok()?;
- let guild = cache.guild(self.guild_id)?;
- let reader = guild.borrow();
-
- let mut highest = None;
-
- for role_id in &self.roles {
- let role = reader.roles
- .get(&role_id)
- .and_then(|x| x.try_borrow().ok());
-
- if let Some(role) = role {
- // Skip this role if this role in iteration has:
- //
- // - a position less than the recorded highest
- // - a position equal to the recorded, but a higher ID
- if let Some((id, pos)) = highest {
- if role.position < pos || (role.position == pos && role.id > id) {
- continue;
- }
- }
-
- highest = Some((role.id, role.position));
- }
- }
-
- highest
- }
-
- /// Kick the member from the guild.
- ///
- /// **Note**: Requires the [Kick Members] permission.
- ///
- /// # Examples
- ///
- /// Kick a member from its guild:
- ///
- /// ```rust,ignore
- /// // assuming a `member` has already been bound
- /// match member.kick() {
- /// Ok(()) => println!("Successfully kicked member"),
- /// Err(Error::Model(ModelError::GuildNotFound)) => {
- /// println!("Couldn't determine guild of member");
- /// },
- /// Err(Error::Model(ModelError::InvalidPermissions(missing_perms))) => {
- /// println!("Didn't have permissions; missing: {:?}", missing_perms);
- /// },
- /// _ => {},
- /// }
- /// ```
- ///
- /// # Errors
- ///
- /// Returns a [`ModelError::GuildNotFound`] if the Id of the member's guild
- /// could not be determined.
- ///
- /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`]
- /// if the current user does not have permission to perform the kick.
- ///
- /// [`ModelError::GuildNotFound`]: enum.ModelError.html#variant.GuildNotFound
- /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
- /// [Kick Members]: permissions/constant.KICK_MEMBERS.html
- pub fn kick(&self) -> FutureResult<()> {
- let client = ftryopt!(self.client);
-
- #[cfg(feature = "cache")]
- {
- let cache = ftry!(client.cache.try_borrow());
-
- if let Some(guild) = cache.guilds.get(&self.guild_id) {
- let req = Permissions::KICK_MEMBERS;
- let reader = ftry!(guild.try_borrow());
-
- if !reader.has_perms(req) {
- return Box::new(future::err(Error::Model(
- ModelError::InvalidPermissions(req),
- )));
- }
-
- ftry!(reader.check_hierarchy(ftry!(self.user.try_borrow()).id));
- }
- }
-
- let user_id = ftry!(self.user.try_borrow()).id.0;
-
- ftryopt!(self.client).http.kick_member(self.guild_id.0, user_id)
- }
-
- /// Returns the guild-level permissions for the member.
- ///
- /// # Examples
- ///
- /// ```rust,ignore
- /// // assuming there's a `member` variable gotten from anything.
- /// println!("The permission bits for the member are: {}",
- /// member.permissions().expect("permissions").bits);
- /// ```
- ///
- /// # Errors
- ///
- /// Returns a [`ModelError::GuildNotFound`] if the guild the member's in could not be
- /// found in the cache.
- ///
- /// And/or returns [`ModelError::ItemMissing`] if the "default channel" of the guild is not
- /// found.
- ///
- /// [`ModelError::GuildNotFound`]: enum.ModelError.html#variant.GuildNotFound
- /// [`ModelError::ItemMissing`]: enum.ModelError.html#variant.ItemMissing
- #[cfg(feature = "cache")]
- pub fn permissions(&self) -> Result<Permissions> {
- let client = self.client.as_ref().ok_or_else(|| {
- Error::Model(ModelError::ClientNotPresent)
- })?;
- let cache = client.cache.try_borrow()?;
- let guild = match cache.guilds.get(&self.guild_id) {
- Some(guild) => guild,
- None => return Err(From::from(ModelError::GuildNotFound)),
- };
-
- let guild = guild.try_borrow()?;
-
- Ok(guild.member_permissions(self.user.try_borrow()?.id))
- }
-
- /// Removes a [`Role`] from the member.
- ///
- /// **Note**: Requires the [Manage Roles] permission.
- ///
- /// [`Role`]: struct.Role.html
- /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
- #[cfg(feature = "cache")]
- pub fn remove_role<R: Into<RoleId>>(&mut self, role_id: R) -> FutureResult<()> {
- let role_id = role_id.into();
-
- if !self.roles.contains(&role_id) {
- return Box::new(future::ok(()));
- }
-
- ftryopt!(self.client).http.remove_member_role(
- self.guild_id.0,
- self.user.borrow().id.0,
- role_id.0,
- )
- }
-
- /// Removes one or multiple [`Role`]s from the member.
- ///
- /// **Note**: Requires the [Manage Roles] permission.
- ///
- /// [`Role`]: struct.Role.html
- /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
- #[cfg(feature = "cache")]
- pub fn remove_roles(&mut self, role_ids: &[RoleId]) -> FutureResult<()> {
- let mut roles = self.roles.clone();
- roles.retain(|r| !role_ids.contains(r));
-
- ftryopt!(self.client).http.edit_member(
- self.guild_id.0,
- self.user.borrow().id.0,
- |f| f.roles(roles),
- )
- }
-
- /// Retrieves the full role data for the user's roles.
- ///
- /// This is shorthand for manually searching through the CACHE.
- ///
- /// If role data can not be found for the member, then `None` is returned.
- #[cfg(feature = "cache")]
- pub fn roles(&self) -> Option<Vec<Rc<RefCell<Role>>>> {
- let client = self.client.as_ref()?;
- let cache = client.cache.try_borrow().ok()?;
-
- cache.guilds.get(&self.guild_id).and_then(|guild| {
- let guild = guild.try_borrow().ok()?;
-
- let roles = guild
- .roles
- .values()
- .filter(|role| {
- let role = match role.try_borrow() {
- Ok(role) => role,
- Err(_) => return false,
- };
-
- self.roles.contains(&role.id)
- })
- .cloned()
- .collect();
-
- Some(roles)
- })
- }
-
- /// Unbans the [`User`] from the guild.
- ///
- /// **Note**: Requires the [Ban Members] permission.
- ///
- /// # Errors
- ///
- /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`]
- /// if the current user does not have permission to perform bans.
- ///
- /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
- /// [`User`]: struct.User.html
- /// [Ban Members]: permissions/constant.BAN_MEMBERS.html
- #[cfg(feature = "cache")]
- pub fn unban(&self) -> FutureResult<()> {
- ftryopt!(self.client).http.remove_ban(
- self.guild_id.0,
- self.user.borrow().id.0,
- )
- }
}
diff --git a/src/model/guild/mod.rs b/src/model/guild/mod.rs
index 6c0fa82..d2281e9 100644
--- a/src/model/guild/mod.rs
+++ b/src/model/guild/mod.rs
@@ -17,24 +17,15 @@ pub use self::role::*;
pub use self::audit_log::*;
use chrono::{DateTime, FixedOffset};
-use futures::{Future, future};
+use constants::LARGE_THRESHOLD;
use model::prelude::*;
use serde::de::Error as DeError;
use serde_json;
+use std::borrow::Cow;
use std::cell::RefCell;
use std::rc::Rc;
-use super::utils::*;
-use super::WrappedClient;
-use ::FutureResult;
-
-#[cfg(feature = "model")]
-use builder::{EditGuild, EditMember, EditRole};
-#[cfg(feature = "model")]
-use constants::LARGE_THRESHOLD;
-#[cfg(feature = "model")]
use std;
-#[cfg(feature = "model")]
-use std::borrow::Cow;
+use super::utils::*;
/// A representation of a banning of a user.
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Hash, Serialize)]
@@ -143,29 +134,9 @@ pub struct Guild {
/// [`User`]: struct.User.html
#[serde(serialize_with = "serialize_gen_map")]
pub voice_states: HashMap<UserId, VoiceState>,
- #[serde(skip)]
- pub(crate) client: WrappedClient,
}
-#[cfg(feature = "model")]
impl Guild {
- #[cfg(feature = "cache")]
- fn check_hierarchy(&self, other_user: UserId) -> Result<()> {
- let client = self.client.as_ref().ok_or_else(|| {
- Error::Model(ModelError::ClientNotPresent)
- })?;
-
- let current_id = client.cache.try_borrow()?.user.id;
-
- if let Some(higher) = self.greater_member_hierarchy(other_user, current_id) {
- if higher != current_id {
- return Err(Error::Model(ModelError::Hierarchy));
- }
- }
-
- Ok(())
- }
-
/// Returns the "default" channel of the guild for the passed user id.
/// (This returns the first channel that can be read by the user, if there isn't one,
/// returns `None`)
@@ -196,569 +167,6 @@ impl Guild {
None
}
- #[cfg(feature = "cache")]
- fn has_perms(&self, mut permissions: Permissions) -> bool {
- let client = match self.client.as_ref() {
- Some(client) => client,
- None => return true,
- };
- let cache = match client.cache.try_borrow() {
- Ok(cache) => cache,
- Err(_) => return true,
- };
-
- let user_id = cache.user.id;
-
- let perms = self.member_permissions(user_id);
- permissions.remove(perms);
-
- permissions.is_empty()
- }
-
- /// Ban a [`User`] from the guild. All messages by the
- /// user within the last given number of days given will be deleted.
- ///
- /// Refer to the documentation for [`Guild::ban`] for more information.
- ///
- /// **Note**: Requires the [Ban Members] permission.
- ///
- /// # Examples
- ///
- /// Ban a member and remove all messages they've sent in the last 4 days:
- ///
- /// ```rust,ignore
- /// // assumes a `user` and `guild` have already been bound
- /// let _ = guild.ban(user, 4);
- /// ```
- ///
- /// # Errors
- ///
- /// Returns a [`ModelError::InvalidPermissions`] if the current user does
- /// not have permission to perform bans.
- ///
- /// Returns a [`ModelError::DeleteMessageDaysAmount`] if the number of
- /// days' worth of messages to delete is over the maximum.
- ///
- /// [`ModelError::DeleteMessageDaysAmount`]:
- /// enum.ModelError.html#variant.DeleteMessageDaysAmount
- /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
- /// [`Guild::ban`]: struct.Guild.html#method.ban
- /// [`User`]: struct.User.html
- /// [Ban Members]: permissions/constant.BAN_MEMBERS.html
- pub fn ban<U: Into<UserId>, BO: BanOptions>(&self, user: U, options: &BO)
- -> FutureResult<()> {
- let user = user.into();
-
- #[cfg(feature = "cache")]
- {
- let req = Permissions::BAN_MEMBERS;
-
- if !self.has_perms(req) {
- return Box::new(future::err(Error::Model(
- ModelError::InvalidPermissions(req),
- )));
- }
-
- ftry!(self.check_hierarchy(user));
- }
-
- let dmd = options.dmd();
- if dmd > 7 {
- return Box::new(future::err(Error::Model(
- ModelError::DeleteMessageDaysAmount(dmd),
- )));
- }
-
- let reason = options.reason();
-
- if reason.len() > 512 {
- return Box::new(future::err(Error::ExceededLimit(
- reason.to_string(),
- 512,
- )));
- }
-
- ftryopt!(self.client)
- .http
- .ban_user(self.id.0, user.0, dmd, reason)
- }
-
- /// Retrieves a list of [`Ban`]s for the guild.
- ///
- /// **Note**: Requires the [Ban Members] permission.
- ///
- /// # Errors
- ///
- /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`]
- /// if the current user does not have permission to perform bans.
- ///
- /// [`Ban`]: struct.Ban.html
- /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
- /// [Ban Members]: permissions/constant.BAN_MEMBERS.html
- pub fn bans(&self) -> FutureResult<Vec<Ban>> {
- #[cfg(feature = "cache")]
- {
- let req = Permissions::BAN_MEMBERS;
-
- if !self.has_perms(req) {
- return Box::new(future::err(Error::Model(
- ModelError::InvalidPermissions(req),
- )));
- }
- }
-
- ftryopt!(self.client).http.get_bans(self.id.0)
- }
-
- /// Retrieves a list of [`AuditLogs`] for the guild.
- ///
- /// [`AuditLogs`]: audit_log/struct.AuditLogs.html
- #[inline]
- pub fn audit_logs(
- &self,
- action_type: Option<u8>,
- user_id: Option<UserId>,
- before: Option<AuditLogEntryId>,
- limit: Option<u8>,
- ) -> FutureResult<AuditLogs> {
- ftryopt!(self.client).http.get_audit_logs(
- self.id.0,
- action_type,
- user_id.map(|x| x.0),
- before.map(|x| x.0),
- limit,
- )
- }
-
- /// Gets all of the guild's channels over the REST API.
- ///
- /// [`Guild`]: struct.Guild.html
- #[inline]
- pub fn channels(&self) -> FutureResult<HashMap<ChannelId, GuildChannel>> {
- let done = ftryopt!(self.client)
- .http
- .get_channels(self.id.0)
- .map(|channels| {
- let mut map = HashMap::with_capacity(channels.len());
-
- for channel in channels {
- map.insert(channel.id, channel);
- }
-
- map
- });
-
- Box::new(done)
- }
-
- /// Creates a new [`Channel`] in the guild.
- ///
- /// **Note**: Requires the [Manage Channels] permission.
- ///
- /// # Examples
- ///
- /// ```rust,ignore
- /// use serenity::model::ChannelType;
- ///
- /// // assuming a `guild` has already been bound
- ///
- /// let _ = guild.create_channel("my-test-channel", ChannelType::Text, None);
- /// ```
- ///
- /// # Errors
- ///
- /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`]
- /// if the current user does not have permission to perform bans.
- ///
- /// [`Channel`]: struct.Channel.html
- /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
- /// [Manage Channels]: permissions/constant.MANAGE_CHANNELS.html
- pub fn create_channel<C>(&self, name: &str, kind: ChannelType, category: C)
- -> FutureResult<GuildChannel> where C: Into<Option<ChannelId>> {
- #[cfg(feature = "cache")]
- {
- let req = Permissions::MANAGE_CHANNELS;
-
- if !self.has_perms(req) {
- return Box::new(future::err(Error::Model(
- ModelError::InvalidPermissions(req),
- )));
- }
- }
-
- ftryopt!(self.client).http.create_channel(
- self.id.0,
- name,
- kind,
- category.into().map(|x| x.0),
- )
- }
-
- /// Creates an emoji in the guild with a name and base64-encoded image. The
- /// [`utils::read_image`] function is provided for you as a simple method to
- /// read an image and encode it into base64, if you are reading from the
- /// filesystem.
- ///
- /// The name of the emoji must be at least 2 characters long and can only
- /// contain alphanumeric characters and underscores.
- ///
- /// Requires the [Manage Emojis] permission.
- ///
- /// # Examples
- ///
- /// See the [`EditProfile::avatar`] example for an in-depth example as to
- /// how to read an image from the filesystem and encode it as base64. Most
- /// of the example can be applied similarly for this method.
- ///
- /// [`EditProfile::avatar`]: ../builder/struct.EditProfile.html#method.avatar
- /// [`utils::read_image`]: ../fn.read_image.html
- /// [Manage Emojis]: permissions/constant.MANAGE_EMOJIS.html
- #[inline]
- pub fn create_emoji(&self, name: &str, image: &str) -> FutureResult<Emoji> {
- ftryopt!(self.client).http.create_emoji(self.id.0, name, image)
- }
-
- /// Creates an integration for the guild.
- ///
- /// Requires the [Manage Guild] permission.
- ///
- /// [Manage Guild]: permissions/constant.MANAGE_GUILD.html
- #[inline]
- pub fn create_integration<I>(&self, integration_id: I, kind: &str)
- -> FutureResult<()> where I: Into<IntegrationId> {
- ftryopt!(self.client).http.create_guild_integration(
- self.id.0,
- integration_id.into().0,
- kind,
- )
- }
-
- /// Creates a new role in the guild with the data set, if any.
- ///
- /// **Note**: Requires the [Manage Roles] permission.
- ///
- /// # Examples
- ///
- /// Create a role which can be mentioned, with the name 'test':
- ///
- /// ```rust,ignore
- /// // assuming a `guild` has been bound
- ///
- /// let role = guild.create_role(|r| r.hoist(true).name("role"));
- /// ```
- ///
- /// # Errors
- ///
- /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`]
- /// if the current user does not have permission to perform bans.
- ///
- /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
- /// [`Role`]: struct.Role.html
- /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
- pub fn create_role<F>(&self, f: F) -> FutureResult<Role>
- where F: FnOnce(EditRole) -> EditRole {
- #[cfg(feature = "cache")]
- {
- let req = Permissions::MANAGE_ROLES;
-
- if !self.has_perms(req) {
- return Box::new(future::err(Error::Model(
- ModelError::InvalidPermissions(req),
- )));
- }
- }
-
- ftryopt!(self.client).http.create_role(self.id.0, f)
- }
-
- /// Deletes the current guild if the current user is the owner of the
- /// guild.
- ///
- /// **Note**: Requires the current user to be the owner of the guild.
- ///
- /// # Errors
- ///
- /// If the `cache` is enabled, then returns a [`ModelError::InvalidUser`]
- /// if the current user is not the guild owner.
- ///
- /// [`ModelError::InvalidUser`]: enum.ModelError.html#variant.InvalidUser
- pub fn delete(&self) -> FutureResult<PartialGuild> {
- let client = ftryopt!(self.client);
-
- #[cfg(feature = "cache")]
- {
- let cache = ftry!(client.cache.try_borrow());
-
- if self.owner_id != cache.user.id {
- let req = Permissions::MANAGE_GUILD;
-
- return Box::new(future::err(Error::Model(
- ModelError::InvalidPermissions(req),
- )));
- }
- }
-
- ftryopt!(self.client).http.delete_guild(self.id.0)
- }
-
- /// Deletes an [`Emoji`] from the guild.
- ///
- /// Requires the [Manage Emojis] permission.
- ///
- /// [`Emoji`]: struct.Emoji.html
- /// [Manage Emojis]: permissions/constant.MANAGE_EMOJIS.html
- #[inline]
- pub fn delete_emoji<E: Into<EmojiId>>(&self, emoji_id: E)
- -> FutureResult<()> {
- ftryopt!(self.client).http.delete_emoji(self.id.0, emoji_id.into().0)
- }
-
- /// Deletes an integration by Id from the guild.
- ///
- /// Requires the [Manage Guild] permission.
- ///
- /// [Manage Guild]: permissions/constant.MANAGE_GUILD.html
- #[inline]
- pub fn delete_integration<I: Into<IntegrationId>>(&self, integration_id: I)
- -> FutureResult<()> {
- ftryopt!(self.client).http.delete_guild_integration(
- self.id.0,
- integration_id.into().0,
- )
- }
-
- /// Deletes a [`Role`] by Id from the guild.
- ///
- /// Also see [`Role::delete`] if you have the `cache` and `methods` features
- /// enabled.
- ///
- /// Requires the [Manage Roles] permission.
- ///
- /// [`Role`]: struct.Role.html
- /// [`Role::delete`]: struct.Role.html#method.delete
- /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
- #[inline]
- pub fn delete_role<R: Into<RoleId>>(&self, role_id: R) -> FutureResult<()> {
- ftryopt!(self.client).http.delete_role(self.id.0, role_id.into().0)
- }
-
- /// Edits the current guild with new data where specified.
- ///
- /// Refer to `EditGuild`'s documentation for a full list of methods.
- ///
- /// **Note**: Requires the current user to have the [Manage Guild]
- /// permission.
- ///
- /// # Examples
- ///
- /// Change a guild's icon using a file name "icon.png":
- ///
- /// ```rust,ignore
- /// use serenity::utils;
- ///
- /// // We are using read_image helper function from utils.
- /// let base64_icon = utils::read_image("./icon.png")
- /// .expect("Failed to read image");
- ///
- /// guild.edit(|g| g.icon(base64_icon));
- /// ```
- ///
- /// # Errors
- ///
- /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`]
- /// if the current user does not have permission to perform bans.
- ///
- /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
- /// [Manage Guild]: permissions/constant.MANAGE_GUILD.html
- pub fn edit<F: FnOnce(EditGuild) -> EditGuild>(&self, f: F)
- -> FutureResult<PartialGuild> {
- #[cfg(feature = "cache")]
- {
- let req = Permissions::MANAGE_GUILD;
-
- if !self.has_perms(req) {
- return Box::new(future::err(Error::Model(
- ModelError::InvalidPermissions(req),
- )));
- }
- }
-
- ftryopt!(self.client).http.edit_guild(self.id.0, f)
- }
-
- /// Edits an [`Emoji`]'s name in the guild.
- ///
- /// Also see [`Emoji::edit`] if you have the `cache` and `methods` features
- /// enabled.
- ///
- /// Requires the [Manage Emojis] permission.
- ///
- /// [`Emoji`]: struct.Emoji.html
- /// [`Emoji::edit`]: struct.Emoji.html#method.edit
- /// [Manage Emojis]: permissions/constant.MANAGE_EMOJIS.html
- #[inline]
- pub fn edit_emoji<E: Into<EmojiId>>(&self, emoji_id: E, name: &str)
- -> FutureResult<Emoji> {
- let emoji_id = emoji_id.into().0;
-
- ftryopt!(self.client).http.edit_emoji(self.id.0, emoji_id, name)
- }
-
- /// Edits the properties of member of the guild, such as muting or
- /// nicknaming them.
- ///
- /// Refer to `EditMember`'s documentation for a full list of methods and
- /// permission restrictions.
- ///
- /// # Examples
- ///
- /// Mute a member and set their roles to just one role with a predefined Id:
- ///
- /// ```rust,ignore
- /// guild.edit_member(user_id, |m| m.mute(true).roles(&vec![role_id]));
- /// ```
- #[inline]
- pub fn edit_member<F, U>(&self, user_id: U, f: F) -> FutureResult<()>
- where F: FnOnce(EditMember) -> EditMember, U: Into<UserId> {
- ftryopt!(self.client).http.edit_member(self.id.0, user_id.into().0, f)
- }
-
- /// Edits the current user's nickname for the guild.
- ///
- /// Pass `None` to reset the nickname.
- ///
- /// **Note**: Requires the [Change Nickname] permission.
- ///
- /// # Errors
- ///
- /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`]
- /// if the current user does not have permission to change their own
- /// nickname.
- ///
- /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
- /// [Change Nickname]: permissions/constant.CHANGE_NICKNAME.html
- pub fn edit_nickname(&self, new_nickname: Option<&str>)
- -> FutureResult<()> {
- #[cfg(feature = "cache")]
- {
- let req = Permissions::CHANGE_NICKNAME;
-
- if !self.has_perms(req) {
- return Box::new(future::err(Error::Model(
- ModelError::InvalidPermissions(req),
- )));
- }
- }
-
- ftryopt!(self.client).http.edit_nickname(self.id.0, new_nickname)
- }
-
- /// Edits a role, optionally setting its fields.
- ///
- /// Requires the [Manage Roles] permission.
- ///
- /// # Examples
- ///
- /// Make a role hoisted:
- ///
- /// ```rust,ignore
- /// guild.edit_role(RoleId(7), |r| r.hoist(true));
- /// ```
- ///
- /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
- #[inline]
- pub fn edit_role<F, R>(&self, role_id: R, f: F) -> FutureResult<Role>
- where F: FnOnce(EditRole) -> EditRole, R: Into<RoleId> {
- ftryopt!(self.client).http.edit_role(self.id.0, role_id.into().0, f)
- }
-
- /// Edits the order of [`Role`]s
- /// Requires the [Manage Roles] permission.
- ///
- /// # Examples
- ///
- /// Change the order of a role:
- ///
- /// ```rust,ignore
- /// use serenity::model::RoleId;
- /// guild.edit_role_position(RoleId(8), 2);
- /// ```
- ///
- /// [`Role`]: struct.Role.html
- /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
- #[inline]
- pub fn edit_role_position<R>(&self, role_id: R, position: u64)
- -> FutureResult<Vec<Role>> where R: Into<RoleId> {
- ftryopt!(self.client)
- .http
- .edit_role_position(self.id.0, role_id.into().0, position)
- }
-
- /// Returns which of two [`User`]s has a higher [`Member`] hierarchy.
- ///
- /// Hierarchy is essentially who has the [`Role`] with the highest
- /// [`position`].
- ///
- /// Returns [`None`] if at least one of the given users' member instances
- /// is not present. Returns `None` if the users have the same hierarchy, as
- /// neither are greater than the other.
- ///
- /// If both user IDs are the same, `None` is returned. If one of the users
- /// is the guild owner, their ID is returned.
- #[cfg(feature = "cache")]
- pub fn greater_member_hierarchy<T, U>(&self, lhs_id: T, rhs_id: U)
- -> Option<UserId> where T: Into<UserId>, U: Into<UserId> {
- let lhs_id = lhs_id.into();
- let rhs_id = rhs_id.into();
-
- // Check that the IDs are the same. If they are, neither is greater.
- if lhs_id == rhs_id {
- return None;
- }
-
- // Check if either user is the guild owner.
- if lhs_id == self.owner_id {
- return Some(lhs_id);
- } else if rhs_id == self.owner_id {
- return Some(rhs_id);
- }
-
- let lhs = self.members.get(&lhs_id)?
- .borrow()
- .highest_role_info()
- .unwrap_or((RoleId(0), 0));
- let rhs = self.members.get(&rhs_id)?
- .borrow()
- .highest_role_info()
- .unwrap_or((RoleId(0), 0));
-
- // If LHS and RHS both have no top position or have the same role ID,
- // then no one wins.
- if (lhs.1 == 0 && rhs.1 == 0) || (lhs.0 == rhs.0) {
- return None;
- }
-
- // If LHS's top position is higher than RHS, then LHS wins.
- if lhs.1 > rhs.1 {
- return Some(lhs_id)
- }
-
- // If RHS's top position is higher than LHS, then RHS wins.
- if rhs.1 > lhs.1 {
- return Some(rhs_id);
- }
-
- // If LHS and RHS both have the same position, but LHS has the lower
- // role ID, then LHS wins.
- //
- // If RHS has the higher role ID, then RHS wins.
- if lhs.1 == rhs.1 && lhs.0 < rhs.0 {
- Some(lhs_id)
- } else {
- Some(rhs_id)
- }
- }
-
/// Returns the formatted URL of the guild's icon, if one exists.
pub fn icon_url(&self) -> Option<String> {
self.icon
@@ -766,40 +174,6 @@ impl Guild {
.map(|icon| format!(cdn!("/icons/{}/{}.webp"), self.id, icon))
}
- /// Gets all integration of the guild.
- ///
- /// This performs a request over the REST API.
- #[inline]
- pub fn integrations(&self) -> FutureResult<Vec<Integration>> {
- ftryopt!(self.client).http.get_guild_integrations(self.id.0)
- }
-
- /// Retrieves the active invites for the guild.
- ///
- /// **Note**: Requires the [Manage Guild] permission.
- ///
- /// # Errors
- ///
- /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`]
- /// if the current user does not have permission to perform bans.
- ///
- /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
- /// [Manage Guild]: permissions/constant.MANAGE_GUILD.html
- pub fn invites(&self) -> FutureResult<Vec<RichInvite>> {
- #[cfg(feature = "cache")]
- {
- let req = Permissions::MANAGE_GUILD;
-
- if !self.has_perms(req) {
- return Box::new(future::err(Error::Model(
- ModelError::InvalidPermissions(req),
- )));
- }
- }
-
- ftryopt!(self.client).http.get_guild_invites(self.id.0)
- }
-
/// Checks if the guild is 'large'. A guild is considered large if it has
/// more than 250 members.
#[inline]
@@ -807,47 +181,6 @@ impl Guild {
self.members.len() > LARGE_THRESHOLD as usize
}
- /// Kicks a [`Member`] from the guild.
- ///
- /// Requires the [Kick Members] permission.
- ///
- /// [`Member`]: struct.Member.html
- /// [Kick Members]: permissions/constant.KICK_MEMBERS.html
- #[inline]
- pub fn kick<U: Into<UserId>>(&self, user_id: U) -> FutureResult<()> {
- ftryopt!(self.client).http.kick_member(self.id.0, user_id.into().0)
- }
-
- /// Leaves the guild.
- #[inline]
- pub fn leave(&self) -> FutureResult<()> {
- ftryopt!(self.client).http.leave_guild(self.id.0)
- }
-
- /// Gets a user's [`Member`] for the guild by Id.
- ///
- /// [`Guild`]: struct.Guild.html
- /// [`Member`]: struct.Member.html
- #[inline]
- pub fn member<U: Into<UserId>>(&self, user_id: U) -> FutureResult<Member> {
- ftryopt!(self.client).http.get_member(self.id.0, user_id.into().0)
- }
-
- /// Gets a list of the guild's members.
- ///
- /// Optionally pass in the `limit` to limit the number of results. Maximum
- /// value is 1000. Optionally pass in `after` to offset the results by a
- /// [`User`]'s Id.
- ///
- /// [`User`]: struct.User.html
- #[inline]
- pub fn members<U>(&self, limit: Option<u64>, after: Option<U>)
- -> FutureResult<Vec<Member>> where U: Into<UserId> {
- let after = after.map(Into::into).map(|x| x.0);
-
- ftryopt!(self.client).http.get_guild_members(self.id.0, limit, after)
- }
-
/// Gets a list of all the members (satisfying the status provided to the function) in this
/// guild.
pub fn members_with_status(&self, status: OnlineStatus)
@@ -1251,21 +584,6 @@ impl Guild {
permissions
}
- /// Moves a member to a specific voice channel.
- ///
- /// Requires the [Move Members] permission.
- ///
- /// [Move Members]: permissions/constant.MOVE_MEMBERS.html
- #[inline]
- pub fn move_member<C, U>(&self, user_id: U, channel_id: C)
- -> FutureResult<()> where C: Into<ChannelId>, U: Into<UserId> {
- ftryopt!(self.client).http.edit_member(
- self.id.0,
- user_id.into().0,
- |f| f.voice_channel(channel_id.into().0),
- )
- }
-
/// Alias for [`permissions_in`].
///
/// [`permissions_in`]: #method.permissions_in
@@ -1417,50 +735,6 @@ impl Guild {
permissions
}
- /// Retrieves the count of the number of [`Member`]s that would be pruned
- /// with the number of given days.
- ///
- /// See the documentation on [`GuildPrune`] for more information.
- ///
- /// **Note**: Requires the [Kick Members] permission.
- ///
- /// # Errors
- ///
- /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`]
- /// if the current user does not have permission to perform bans.
- ///
- /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
- /// [`GuildPrune`]: struct.GuildPrune.html
- /// [`Member`]: struct.Member.html
- /// [Kick Members]: permissions/constant.KICK_MEMBERS.html
- pub fn prune_count(&self, days: u16) -> FutureResult<GuildPrune> {
- #[cfg(feature = "cache")]
- {
- let req = Permissions::KICK_MEMBERS;
-
- if !self.has_perms(req) {
- return Box::new(future::err(Error::Model(
- ModelError::InvalidPermissions(req),
- )));
- }
- }
-
- ftryopt!(self.client).http.get_guild_prune_count(self.id.0, days)
- }
-
- /// Re-orders the channels of the guild.
- ///
- /// Although not required, you should specify all channels' positions,
- /// regardless of whether they were updated. Otherwise, positioning can
- /// sometimes get weird.
- pub fn reorder_channels<It>(&self, channels: It) -> FutureResult<()>
- where It: IntoIterator<Item = (ChannelId, u64)> {
- ftryopt!(self.client).http.edit_guild_channel_positions(
- self.id.0,
- channels,
- )
- }
-
/// Returns the Id of the shard associated with the guild.
///
/// When the cache is enabled this will automatically retrieve the total
@@ -1492,87 +766,6 @@ impl Guild {
.map(|icon| format!(cdn!("/splashes/{}/{}.webp"), self.id, icon))
}
- /// Starts an integration sync for the given integration Id.
- ///
- /// Requires the [Manage Guild] permission.
- ///
- /// [Manage Guild]: permissions/constant.MANAGE_GUILD.html
- #[inline]
- pub fn start_integration_sync<I>(&self, integration_id: I)
- -> FutureResult<()> where I: Into<IntegrationId> {
- ftryopt!(self.client).http.start_integration_sync(
- self.id.0,
- integration_id.into().0,
- )
- }
-
- /// Starts a prune of [`Member`]s.
- ///
- /// See the documentation on [`GuildPrune`] for more information.
- ///
- /// **Note**: Requires the [Kick Members] permission.
- ///
- /// # Errors
- ///
- /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`]
- /// if the current user does not have permission to perform bans.
- ///
- /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
- /// [`GuildPrune`]: struct.GuildPrune.html
- /// [`Member`]: struct.Member.html
- /// [Kick Members]: permissions/constant.KICK_MEMBERS.html
- pub fn start_prune(&self, days: u16) -> FutureResult<GuildPrune> {
- #[cfg(feature = "cache")]
- {
- let req = Permissions::KICK_MEMBERS;
-
- if !self.has_perms(req) {
- return Box::new(future::err(Error::Model(
- ModelError::InvalidPermissions(req),
- )));
- }
- }
-
- ftryopt!(self.client).http.start_guild_prune(self.id.0, days)
- }
-
- /// Unbans the given [`User`] from the guild.
- ///
- /// **Note**: Requires the [Ban Members] permission.
- ///
- /// # Errors
- ///
- /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`]
- /// if the current user does not have permission to perform bans.
- ///
- /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
- /// [`User`]: struct.User.html
- /// [Ban Members]: permissions/constant.BAN_MEMBERS.html
- pub fn unban<U: Into<UserId>>(&self, user_id: U) -> FutureResult<()> {
- #[cfg(feature = "cache")]
- {
- let req = Permissions::BAN_MEMBERS;
-
- if !self.has_perms(req) {
- return Box::new(future::err(Error::Model(
- ModelError::InvalidPermissions(req),
- )));
- }
- }
-
- ftryopt!(self.client).http.remove_ban(self.id.0, user_id.into().0)
- }
-
- /// Retrieves the guild's webhooks.
- ///
- /// **Note**: Requires the [Manage Webhooks] permission.
- ///
- /// [Manage Webhooks]: permissions/constant.MANAGE_WEBHOOKS.html
- #[inline]
- pub fn webhooks(&self) -> FutureResult<Vec<Webhook>> {
- ftryopt!(self.client).http.get_guild_webhooks(self.id.0)
- }
-
/// Obtain a reference to a role by its name.
///
/// **Note**: If two or more roles have the same name, obtained reference will be one of
@@ -1752,7 +945,6 @@ impl<'de> Deserialize<'de> for Guild {
application_id: application_id,
afk_timeout: afk_timeout,
channels: channels,
- client: None,
default_message_notifications: default_message_notifications,
emojis: emojis,
explicit_content_filter: explicit_content_filter,
@@ -1778,13 +970,11 @@ impl<'de> Deserialize<'de> for Guild {
}
/// Checks if a `&str` contains another `&str`.
-#[cfg(feature = "model")]
fn contains_case_insensitive(to_look_at: &str, to_find: &str) -> bool {
to_look_at.to_lowercase().contains(to_find)
}
/// Checks if a `&str` starts with another `&str`.
-#[cfg(feature = "model")]
fn starts_with_case_insensitive(to_look_at: &str, to_find: &str) -> bool {
to_look_at.to_lowercase().starts_with(to_find)
}
@@ -1796,7 +986,6 @@ fn starts_with_case_insensitive(to_look_at: &str, to_find: &str) -> bool {
/// expected to contain `origin` as substring.
/// If not, using `closest_to_origin` would sort these
/// the end.
-#[cfg(feature = "model")]
fn closest_to_origin(origin: &str, word_a: &str, word_b: &str) -> std::cmp::Ordering {
let value_a = match word_a.find(origin) {
Some(value) => value + word_a.len(),
@@ -1882,7 +1071,6 @@ impl From<u64> for GuildContainer {
fn from(id: u64) -> GuildContainer { GuildContainer::Id(GuildId(id)) }
}
-#[cfg(feature = "model")]
impl InviteGuild {
/// Returns the formatted URL of the guild's splash image, if one exists.
pub fn splash_url(&self) -> Option<String> {
@@ -1914,7 +1102,6 @@ pub enum GuildStatus {
Offline(GuildUnavailable),
}
-#[cfg(feature = "model")]
impl GuildStatus {
/// Retrieves the Id of the inner [`Guild`].
///
diff --git a/src/model/guild/partial_guild.rs b/src/model/guild/partial_guild.rs
index 6b0b3d2..39f158a 100644
--- a/src/model/guild/partial_guild.rs
+++ b/src/model/guild/partial_guild.rs
@@ -1,13 +1,8 @@
-use futures::{Future, future};
use model::prelude::*;
use std::cell::RefCell;
use std::rc::Rc;
use super::super::utils::{deserialize_emojis, deserialize_roles};
-use super::super::WrappedClient;
-use ::FutureResult;
-#[cfg(feature = "model")]
-use builder::{EditGuild, EditMember, EditRole};
/// Partial information about a [`Guild`]. This does not include information
/// like member data.
@@ -38,304 +33,9 @@ pub struct PartialGuild {
pub roles: HashMap<RoleId, Rc<RefCell<Role>>>,
pub splash: Option<String>,
pub verification_level: VerificationLevel,
- #[serde(skip)]
- pub(crate) client: WrappedClient,
}
-#[cfg(feature = "model")]
impl PartialGuild {
- /// Ban a [`User`] from the guild. All messages by the
- /// user within the last given number of days given will be deleted. This
- /// may be a range between `0` and `7`.
- ///
- /// **Note**: Requires the [Ban Members] permission.
- ///
- /// # Examples
- ///
- /// Ban a member and remove all messages they've sent in the last 4 days:
- ///
- /// ```rust,ignore
- /// // assumes a `user` and `guild` have already been bound
- /// let _ = guild.ban(user, 4);
- /// ```
- ///
- /// # Errors
- ///
- /// Returns a [`ModelError::DeleteMessageDaysAmount`] if the number of
- /// days' worth of messages to delete is over the maximum.
- ///
- /// [`ModelError::DeleteMessageDaysAmount`]:
- /// enum.ModelError.html#variant.DeleteMessageDaysAmount
- /// [`User`]: struct.User.html
- /// [Ban Members]: permissions/constant.BAN_MEMBERS.html
- // todo: add ban reason
- pub fn ban<U: Into<UserId>>(&self, user_id: U, delete_message_days: u8)
- -> FutureResult<()> {
- if delete_message_days > 7 {
- return Box::new(future::err(Error::Model(
- ModelError::DeleteMessageDaysAmount(delete_message_days),
- )));
- }
-
- Box::new(ftryopt!(self.client).http.ban_user(
- self.id.0,
- user_id.into().0,
- delete_message_days,
- "",
- ))
- }
-
- /// Gets a list of the guild's bans.
- ///
- /// Requires the [Ban Members] permission.
- ///
- /// [Ban Members]: permissions/constant.BAN_MEMBERS.html
- #[inline]
- pub fn bans(&self) -> FutureResult<Vec<Ban>> {
- ftryopt!(self.client).http.get_bans(self.id.0)
- }
-
- /// Gets all of the guild's channels over the REST API.
- ///
- /// [`Guild`]: struct.Guild.html
- #[inline]
- pub fn channels(&self) -> FutureResult<HashMap<ChannelId, GuildChannel>> {
- let done = ftryopt!(self.client)
- .http
- .get_channels(self.id.0)
- .map(|channels| {
- let mut map = HashMap::with_capacity(channels.len());
-
- for channel in channels {
- map.insert(channel.id, channel);
- }
-
- map
- });
-
- Box::new(done)
- }
-
- /// Creates a [`GuildChannel`] in the guild.
- ///
- /// Refer to [`http::create_channel`] for more information.
- ///
- /// Requires the [Manage Channels] permission.
- ///
- /// # Examples
- ///
- /// Create a voice channel in a guild with the name `test`:
- ///
- /// ```rust,ignore
- /// use serenity::model::ChannelType;
- ///
- /// guild.create_channel("test", ChannelType::Voice, None);
- /// ```
- ///
- /// [`GuildChannel`]: struct.GuildChannel.html
- /// [`http::create_channel`]: ../http/fn.create_channel.html
- /// [Manage Channels]: permissions/constant.MANAGE_CHANNELS.html
- #[inline]
- pub fn create_channel<C>(&self, name: &str, kind: ChannelType, category: C)
- -> FutureResult<GuildChannel> where C: Into<Option<ChannelId>> {
- ftryopt!(self.client).http.create_channel(
- self.id.0,
- name,
- kind,
- category.into().map(|x| x.0),
- )
- }
-
- /// Creates an emoji in the guild with a name and base64-encoded image.
- ///
- /// Refer to the documentation for [`Guild::create_emoji`] for more
- /// information.
- ///
- /// Requires the [Manage Emojis] permission.
- ///
- /// # Examples
- ///
- /// See the [`EditProfile::avatar`] example for an in-depth example as to
- /// how to read an image from the filesystem and encode it as base64. Most
- /// of the example can be applied similarly for this method.
- ///
- /// [`EditProfile::avatar`]: ../builder/struct.EditProfile.html#method.avatar
- /// [`Guild::create_emoji`]: struct.Guild.html#method.create_emoji
- /// [`utils::read_image`]: ../utils/fn.read_image.html
- /// [Manage Emojis]: permissions/constant.MANAGE_EMOJIS.html
- #[inline]
- pub fn create_emoji(&self, name: &str, image: &str) -> FutureResult<Emoji> {
- ftryopt!(self.client).http.create_emoji(self.id.0, name, image)
- }
-
- /// Creates an integration for the guild.
- ///
- /// Requires the [Manage Guild] permission.
- ///
- /// [Manage Guild]: permissions/constant.MANAGE_GUILD.html
- #[inline]
- pub fn create_integration<I>(&self, integration_id: I, kind: &str)
- -> FutureResult<()> where I: Into<IntegrationId> {
- ftryopt!(self.client).http.create_guild_integration(
- self.id.0,
- integration_id.into().0,
- kind,
- )
- }
-
- /// Creates a new role in the guild with the data set, if any.
- ///
- /// See the documentation for [`Guild::create_role`] on how to use this.
- ///
- /// **Note**: Requires the [Manage Roles] permission.
- ///
- /// # Errors
- ///
- /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`]
- /// if the current user does not have permission to perform bans.
- ///
- /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
- /// [`Guild::create_role`]: struct.Guild.html#method.create_role
- /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
- #[inline]
- pub fn create_role<F: FnOnce(EditRole) -> EditRole>(&self, f: F)
- -> FutureResult<Role> {
- ftryopt!(self.client).http.create_role(self.id.0, f)
- }
-
- /// Deletes the current guild if the current user is the owner of the
- /// guild.
- ///
- /// **Note**: Requires the current user to be the owner of the guild.
- #[inline]
- pub fn delete(&self) -> FutureResult<PartialGuild> {
- ftryopt!(self.client).http.delete_guild(self.id.0)
- }
-
- /// Deletes an [`Emoji`] from the guild.
- ///
- /// Requires the [Manage Emojis] permission.
- ///
- /// [`Emoji`]: struct.Emoji.html
- /// [Manage Emojis]: permissions/constant.MANAGE_EMOJIS.html
- #[inline]
- pub fn delete_emoji<E: Into<EmojiId>>(&self, emoji_id: E)
- -> FutureResult<()> {
- ftryopt!(self.client).http.delete_emoji(self.id.0, emoji_id.into().0)
- }
-
- /// Deletes an integration by Id from the guild.
- ///
- /// Requires the [Manage Guild] permission.
- ///
- /// [Manage Guild]: permissions/constant.MANAGE_GUILD.html
- #[inline]
- pub fn delete_integration<I: Into<IntegrationId>>(&self, integration_id: I)
- -> FutureResult<()> {
- ftryopt!(self.client).http.delete_guild_integration(
- self.id.0,
- integration_id.into().0,
- )
- }
-
- /// Deletes a [`Role`] by Id from the guild.
- ///
- /// Also see [`Role::delete`] if you have the `cache` and `methods` features
- /// enabled.
- ///
- /// Requires the [Manage Roles] permission.
- ///
- /// [`Role`]: struct.Role.html
- /// [`Role::delete`]: struct.Role.html#method.delete
- /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
- #[inline]
- pub fn delete_role<R: Into<RoleId>>(&self, role_id: R) -> FutureResult<()> {
- let role_id = role_id.into().0;
-
- ftryopt!(self.client).http.delete_role(self.id.0, role_id)
- }
-
- /// Edits the current guild with new data where specified.
- ///
- /// **Note**: Requires the current user to have the [Manage Guild]
- /// permission.
- ///
- /// [Manage Guild]: permissions/constant.MANAGE_GUILD.html
- pub fn edit<'a, F: FnOnce(EditGuild) -> EditGuild>(&self, f: F)
- -> FutureResult<PartialGuild> {
- ftryopt!(self.client).http.edit_guild(self.id.0, f)
- }
-
- /// Edits an [`Emoji`]'s name in the guild.
- ///
- /// Also see [`Emoji::edit`] if you have the `cache` and `methods` features
- /// enabled.
- ///
- /// Requires the [Manage Emojis] permission.
- ///
- /// [`Emoji`]: struct.Emoji.html
- /// [`Emoji::edit`]: struct.Emoji.html#method.edit
- /// [Manage Emojis]: permissions/constant.MANAGE_EMOJIS.html
- #[inline]
- pub fn edit_emoji<E: Into<EmojiId>>(&self, emoji_id: E, name: &str)
- -> FutureResult<Emoji> {
- ftryopt!(self.client)
- .http
- .edit_emoji(self.id.0, emoji_id.into().0, name)
- }
-
- /// Edits the properties of member of the guild, such as muting or
- /// nicknaming them.
- ///
- /// Refer to `EditMember`'s documentation for a full list of methods and
- /// permission restrictions.
- ///
- /// # Examples
- ///
- /// Mute a member and set their roles to just one role with a predefined Id:
- ///
- /// ```rust,ignore
- /// use serenity::model::GuildId;
- ///
- /// GuildId(7).edit_member(user_id, |m| m.mute(true).roles(&vec![role_id]));
- /// ```
- #[inline]
- pub fn edit_member<F, U>(&self, user_id: U, f: F) -> FutureResult<()>
- where F: FnOnce(EditMember) -> EditMember, U: Into<UserId> {
- ftryopt!(self.client).http.edit_member(self.id.0, user_id.into().0, f)
- }
-
- /// Edits the current user's nickname for the guild.
- ///
- /// Pass `None` to reset the nickname.
- ///
- /// **Note**: Requires the [Change Nickname] permission.
- ///
- /// # Errors
- ///
- /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`]
- /// if the current user does not have permission to change their own
- /// nickname.
- ///
- /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
- /// [Change Nickname]: permissions/constant.CHANGE_NICKNAME.html
- #[inline]
- pub fn edit_nickname(&self, new_nickname: Option<&str>)
- -> FutureResult<()> {
- ftryopt!(self.client).http.edit_nickname(self.id.0, new_nickname)
- }
-
- /// Kicks a [`Member`] from the guild.
- ///
- /// Requires the [Kick Members] permission.
- ///
- /// [`Member`]: struct.Member.html
- /// [Kick Members]: permissions/constant.KICK_MEMBERS.html
- #[inline]
- pub fn kick<U: Into<UserId>>(&self, user_id: U) -> FutureResult<()> {
- ftryopt!(self.client).http.kick_member(self.id.0, user_id.into().0)
- }
-
/// Returns a formatted URL of the guild's icon, if the guild has an icon.
pub fn icon_url(&self) -> Option<String> {
self.icon
@@ -343,78 +43,6 @@ impl PartialGuild {
.map(|icon| format!(cdn!("/icons/{}/{}.webp"), self.id, icon))
}
- /// Gets all integration of the guild.
- ///
- /// This performs a request over the REST API.
- #[inline]
- pub fn integrations(&self) -> FutureResult<Vec<Integration>> {
- ftryopt!(self.client).http.get_guild_integrations(self.id.0)
- }
-
- /// Gets all of the guild's invites.
- ///
- /// Requires the [Manage Guild] permission.
- ///
- /// [Manage Guild]: permissions/constant.MANAGE_GUILD.html
- #[inline]
- pub fn invites(&self) -> FutureResult<Vec<RichInvite>> {
- ftryopt!(self.client).http.get_guild_invites(self.id.0)
- }
-
- /// Leaves the guild.
- #[inline]
- pub fn leave(&self) -> FutureResult<()> {
- ftryopt!(self.client).http.leave_guild(self.id.0)
- }
-
- /// Gets a user's [`Member`] for the guild by Id.
- ///
- /// [`Guild`]: struct.Guild.html
- /// [`Member`]: struct.Member.html
- pub fn member<U: Into<UserId>>(&self, user_id: U) -> FutureResult<Member> {
- ftryopt!(self.client).http.get_member(self.id.0, user_id.into().0)
- }
-
- /// Gets a list of the guild's members.
- ///
- /// Optionally pass in the `limit` to limit the number of results. Maximum
- /// value is 1000. Optionally pass in `after` to offset the results by a
- /// [`User`]'s Id.
- ///
- /// [`User`]: struct.User.html
- pub fn members<U: Into<UserId>>(&self, limit: Option<u64>, after: Option<U>)
- -> FutureResult<Vec<Member>> {
- let after = after.map(Into::into).map(|x| x.0);
-
- ftryopt!(self.client).http.get_guild_members(self.id.0, limit, after)
- }
-
- /// Moves a member to a specific voice channel.
- ///
- /// Requires the [Move Members] permission.
- ///
- /// [Move Members]: permissions/constant.MOVE_MEMBERS.html
- #[inline]
- pub fn move_member<C, U>(&self, user_id: U, channel_id: C)
- -> FutureResult<()> where C: Into<ChannelId>, U: Into<UserId> {
- ftryopt!(self.client)
- .http
- .edit_member(self.id.0, user_id.into().0, |f| f
- .voice_channel(channel_id.into().0))
- }
-
- /// Gets the number of [`Member`]s that would be pruned with the given
- /// number of days.
- ///
- /// Requires the [Kick Members] permission.
- ///
- /// [`Member`]: struct.Member.html
- /// [Kick Members]: permissions/constant.KICK_MEMBERS.html
- #[inline]
- pub fn prune_count(&self, days: u16) -> FutureResult<GuildPrune> {
- ftryopt!(self.client).http.get_guild_prune_count(self.id.0, days)
- }
-
/// Returns the Id of the shard associated with the guild.
///
/// When the cache is enabled this will automatically retrieve the total
@@ -446,40 +74,6 @@ impl PartialGuild {
.map(|icon| format!(cdn!("/splashes/{}/{}.webp"), self.id, icon))
}
- /// Starts an integration sync for the given integration Id.
- ///
- /// Requires the [Manage Guild] permission.
- ///
- /// [Manage Guild]: permissions/constant.MANAGE_GUILD.html
- #[inline]
- pub fn start_integration_sync<I>(&self, integration_id: I)
- -> FutureResult<()> where I: Into<IntegrationId> {
- ftryopt!(self.client)
- .http
- .start_integration_sync(self.id.0, integration_id.into().0)
- }
-
- /// Unbans a [`User`] from the guild.
- ///
- /// Requires the [Ban Members] permission.
- ///
- /// [`User`]: struct.User.html
- /// [Ban Members]: permissions/constant.BAN_MEMBERS.html
- #[inline]
- pub fn unban<U: Into<UserId>>(&self, user_id: U) -> FutureResult<()> {
- ftryopt!(self.client).http.remove_ban(self.id.0, user_id.into().0)
- }
-
- /// Retrieves the guild's webhooks.
- ///
- /// **Note**: Requires the [Manage Webhooks] permission.
- ///
- /// [Manage Webhooks]: permissions/constant.MANAGE_WEBHOOKS.html
- #[inline]
- pub fn webhooks(&self) -> FutureResult<Vec<Webhook>> {
- ftryopt!(self.client).http.get_guild_webhooks(self.id.0)
- }
-
/// Obtain a reference to a role by its name.
///
/// **Note**: If two or more roles have the same name, obtained reference will be one of
diff --git a/src/model/guild/role.rs b/src/model/guild/role.rs
index bcb142a..bdc6e77 100644
--- a/src/model/guild/role.rs
+++ b/src/model/guild/role.rs
@@ -1,12 +1,5 @@
use model::prelude::*;
use std::cmp::Ordering;
-use super::super::WrappedClient;
-use ::FutureResult;
-
-#[cfg(all(feature = "builder", feature = "cache", feature = "model"))]
-use builder::EditRole;
-#[cfg(all(feature = "cache", feature = "model"))]
-use internal::prelude::*;
/// Information about a role within a guild. A role represents a set of
/// permissions, and can be attached to one or multiple users. A role has
@@ -57,76 +50,9 @@ pub struct Role {
///
/// The `@everyone` role is usually either `-1` or `0`.
pub position: i64,
- #[serde(skip)]
- pub(crate) client: WrappedClient,
}
-#[cfg(feature = "model")]
impl Role {
- /// Deletes the role.
- ///
- /// **Note** Requires the [Manage Roles] permission.
- ///
- /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
- #[cfg(feature = "cache")]
- #[inline]
- pub fn delete(&self) -> FutureResult<()> {
- let guild_id = ftry!(self.find_guild());
-
- ftryopt!(self.client).http.delete_role(guild_id.0, self.id.0)
- }
-
- /// Edits a [`Role`], optionally setting its new fields.
- ///
- /// Requires the [Manage Roles] permission.
- ///
- /// # Examples
- ///
- /// Make a role hoisted:
- ///
- /// ```rust,no_run
- /// # use serenity::model::id::RoleId;
- /// # let role = RoleId(7).find().unwrap();
- /// // assuming a `role` has already been bound
- //
- /// role.edit(|r| r.hoist(true));
- /// ```
- ///
- /// [`Role`]: struct.Role.html
- /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
- #[cfg(all(feature = "builder", feature = "cache"))]
- pub fn edit<F: FnOnce(EditRole) -> EditRole>(&self, f: F)
- -> FutureResult<Role> {
- let guild_id = ftry!(self.find_guild());
-
- ftryopt!(self.client).http.edit_role(guild_id.0, self.id.0, f)
- }
-
- /// Searches the cache for the guild that owns the role.
- ///
- /// # Errors
- ///
- /// Returns a [`ModelError::GuildNotFound`] if a guild is not in the cache
- /// that contains the role.
- ///
- /// [`ModelError::GuildNotFound`]: enum.ModelError.html#variant.GuildNotFound
- #[cfg(feature = "cache")]
- pub fn find_guild(&self) -> Result<GuildId> {
- let client = self.client.as_ref().ok_or_else(|| {
- Error::Model(ModelError::ClientNotPresent)
- })?;
-
- for guild in client.cache.borrow().guilds.values() {
- let guild = guild.borrow();
-
- if guild.roles.contains_key(&RoleId(self.id.0)) {
- return Ok(guild.id);
- }
- }
-
- Err(Error::Model(ModelError::GuildNotFound))
- }
-
/// Check that the role has the given permission.
#[inline]
pub fn has_permission(&self, permission: Permissions) -> bool {
diff --git a/src/model/invite.rs b/src/model/invite.rs
index 3be7f47..63929e9 100644
--- a/src/model/invite.rs
+++ b/src/model/invite.rs
@@ -1,13 +1,7 @@
//! Models for server and channel invites.
use chrono::{DateTime, FixedOffset};
-use futures::future;
use super::prelude::*;
-use super::WrappedClient;
-use ::FutureResult;
-
-#[cfg(all(feature = "cache", feature = "model"))]
-use super::Permissions;
/// Information about an invite code.
///
@@ -37,43 +31,9 @@ pub struct Invite {
/// a representation of the minimal amount of information needed about the
/// [`Guild`] being invited to.
pub guild: InviteGuild,
- #[serde(skip)]
- pub(crate) client: WrappedClient,
}
-#[cfg(feature = "model")]
impl Invite {
- /// Deletes the invite.
- ///
- /// **Note**: Requires the [Manage Guild] permission.
- ///
- /// # Errors
- ///
- /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`]
- /// if the current user does not have the required [permission].
- ///
- /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
- /// [Manage Guild]: permissions/constant.MANAGE_GUILD.html
- /// [permission]: permissions/index.html
- pub fn delete(&self) -> FutureResult<Invite> {
- let client = ftryopt!(self.client);
-
- #[cfg(feature = "cache")]
- {
- let cache = ftry!(client.cache.try_borrow());
-
- let req = Permissions::MANAGE_GUILD;
-
- if !ftry!(cache.user_has_perms(self.channel.id, req)) {
- return Box::new(future::err(Error::Model(
- ModelError::InvalidPermissions(req),
- )));
- }
- }
-
- ftryopt!(self.client).http.delete_invite(&self.code)
- }
-
/// Returns a URL to use for the invite.
///
/// # Examples
@@ -126,7 +86,6 @@ pub struct InviteGuild {
pub voice_channel_count: Option<u64>,
}
-#[cfg(feature = "model")]
impl InviteGuild {
/// Returns the Id of the shard associated with the guild.
///
@@ -194,48 +153,9 @@ pub struct RichInvite {
pub temporary: bool,
/// The amount of times that an invite has been used.
pub uses: u64,
- #[serde(skip)]
- pub(crate) client: WrappedClient,
}
-#[cfg(feature = "model")]
impl RichInvite {
- /// Deletes the invite.
- ///
- /// Refer to [`http::delete_invite`] for more information.
- ///
- /// **Note**: Requires the [Manage Guild] permission.
- ///
- /// # Errors
- ///
- /// If the `cache` feature is enabled, then this returns a
- /// [`ModelError::InvalidPermissions`] if the current user does not have
- /// the required [permission].
- ///
- /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
- /// [`Invite::delete`]: struct.Invite.html#method.delete
- /// [`http::delete_invite`]: ../http/fn.delete_invite.html
- /// [Manage Guild]: permissions/constant.MANAGE_GUILD.html
- /// [permission]: permissions/index.html
- pub fn delete(&self) -> FutureResult<Invite> {
- let client = ftryopt!(self.client);
-
- #[cfg(feature = "cache")]
- {
- let cache = ftry!(client.cache.try_borrow());
-
- let req = Permissions::MANAGE_GUILD;
-
- if !ftry!(cache.user_has_perms(self.channel.id, req)) {
- return Box::new(future::err(Error::Model(
- ModelError::InvalidPermissions(req),
- )));
- }
- }
-
- ftryopt!(self.client).http.delete_invite(&self.code)
- }
-
/// Returns a URL to use for the invite.
///
/// # Examples
diff --git a/src/model/mod.rs b/src/model/mod.rs
index 44a4a3e..bc059ee 100644
--- a/src/model/mod.rs
+++ b/src/model/mod.rs
@@ -40,7 +40,6 @@ pub mod webhook;
pub use self::error::Error as ModelError;
pub use self::permissions::Permissions;
-use client::Client;
use internal::prelude::*;
use self::utils::*;
use serde::de::Visitor;
@@ -52,5 +51,3 @@ use std::result::Result as StdResult;
#[cfg(feature = "utils")]
use utils::Colour;
-
-type WrappedClient = Option<Rc<Client>>;
diff --git a/src/model/permissions.rs b/src/model/permissions.rs
index dbf0b69..310f8dd 100644
--- a/src/model/permissions.rs
+++ b/src/model/permissions.rs
@@ -254,7 +254,6 @@ bitflags! {
}
}
-#[cfg(feature = "model")]
impl Permissions {
/// Shorthand for checking that the set of permissions contains the
/// [Add Reactions] permission.
diff --git a/src/model/user.rs b/src/model/user.rs
index efc880a..86907cd 100644
--- a/src/model/user.rs
+++ b/src/model/user.rs
@@ -1,25 +1,14 @@
//! User information-related models.
-use futures::{Future, future};
use serde_json;
use std::fmt;
use super::utils::deserialize_u16;
use super::prelude::*;
-use super::WrappedClient;
-use ::FutureResult;
use internal::prelude::*;
use model::misc::Mentionable;
-#[cfg(feature = "model")]
-use builder::{CreateMessage, EditProfile};
-#[cfg(feature = "model")]
use chrono::NaiveDateTime;
-#[cfg(feature = "model")]
-use http::GuildPagination;
-#[cfg(feature = "model")]
use std::fmt::Write;
-#[cfg(feature = "model")]
-use utils::{self, VecMap};
/// Information about the current user.
#[derive(Clone, Default, Debug, Deserialize, Serialize)]
@@ -32,11 +21,8 @@ pub struct CurrentUser {
pub mfa_enabled: bool,
#[serde(rename = "username")] pub name: String,
pub verified: bool,
- #[serde(skip)]
- pub(crate) client: WrappedClient,
}
-#[cfg(feature = "model")]
impl CurrentUser {
/// Returns the formatted URL of the user's icon, if one exists.
///
@@ -68,38 +54,6 @@ impl CurrentUser {
#[inline]
pub fn default_avatar_url(&self) -> String { default_avatar_url(self.discriminator) }
- /// Edits the current user's profile settings.
- ///
- /// This mutates the current user in-place.
- ///
- /// Refer to `EditProfile`'s documentation for its methods.
- ///
- /// # Examples
- ///
- /// Change the avatar:
- ///
- /// ```rust,ignore
- /// use serenity::CACHE;
- ///
- /// let avatar = serenity::utils::read_image("./avatar.png").unwrap();
- ///
- /// CACHE.write().user.edit(|p| p.avatar(Some(&avatar)));
- /// ```
- pub fn edit<F: FnOnce(EditProfile) -> EditProfile>(&mut self, f: F)
- -> Box<Future<Item = CurrentUser, Error = Error>> {
- let mut map = VecMap::new();
- map.insert("username", Value::String(self.name.clone()));
-
- if let Some(email) = self.email.as_ref() {
- map.insert("email", Value::String(email.clone()));
- }
-
- let map = utils::vecmap_to_json_map(f(EditProfile(map)).0);
- let value = Value::Object(map);
-
- ftryopt!(self.client).http.edit_profile(&value)
- }
-
/// Retrieves the URL to the current user's avatar, falling back to the
/// default avatar if needed.
///
@@ -113,119 +67,6 @@ impl CurrentUser {
.unwrap_or_else(|| self.default_avatar_url())
}
- /// Gets a list of guilds that the current user is in.
- ///
- /// # Examples
- ///
- /// Print out the names of all guilds the current user is in:
- ///
- /// ```rust,no_run
- /// # use serenity::CACHE;
- /// #
- /// # let cache = CACHE.read();
- /// #
- /// // assuming the cache has been unlocked
- /// let user = &cache.user;
- ///
- /// if let Ok(guilds) = user.guilds() {
- /// for (index, guild) in guilds.into_iter().enumerate() {
- /// println!("{}: {}", index, guild.name);
- /// }
- /// }
- /// ```
- pub fn guilds(&self) -> FutureResult<Vec<GuildInfo>> {
- ftryopt!(self.client)
- .http
- .get_guilds(&GuildPagination::After(GuildId(1)), 100)
- }
-
- /// Returns the invite url for the bot with the given permissions.
- ///
- /// This queries the REST API for the client id.
- ///
- /// If the permissions passed are empty, the permissions part will be dropped.
- ///
- /// # Examples
- ///
- /// Get the invite url with no permissions set:
- ///
- /// ```rust,no_run
- /// # use serenity::CACHE;
- /// #
- /// # let mut cache = CACHE.write();
- ///
- /// use serenity::model::Permissions;
- ///
- /// // assuming the cache has been unlocked
- /// let url = match cache.user.invite_url(Permissions::empty()) {
- /// Ok(v) => v,
- /// Err(why) => {
- /// println!("Error getting invite url: {:?}", why);
- ///
- /// return;
- /// },
- /// };
- ///
- /// assert_eq!(url, "https://discordapp.com/api/oauth2/authorize? \
- /// client_id=249608697955745802&scope=bot");
- /// ```
- ///
- /// Get the invite url with some basic permissions set:
- ///
- /// ```rust,no_run
- /// # use serenity::CACHE;
- /// #
- /// # let mut cache = CACHE.write();
- ///
- /// use serenity::model::Permissions;
- ///
- /// // assuming the cache has been unlocked
- /// let url = match cache.user.invite_url(Permissions::READ_MESSAGES | Permissions::SEND_MESSAGES | Permissions::EMBED_LINKS) {
- /// Ok(v) => v,
- /// Err(why) => {
- /// println!("Error getting invite url: {:?}", why);
- ///
- /// return;
- /// },
- /// };
- ///
- /// assert_eq!(url,
- /// "https://discordapp.
- /// com/api/oauth2/authorize?client_id=249608697955745802&scope=bot&permissions=19456");
- /// ```
- ///
- /// # Errors
- ///
- /// Returns an
- /// [`HttpError::InvalidRequest(Unauthorized)`][`HttpError::InvalidRequest`]
- /// If the user is not authorized for this end point.
- ///
- /// May return [`Error::Format`] while writing url to the buffer.
- ///
- /// [`Error::Format`]: ../enum.Error.html#variant.Format
- /// [`HttpError::InvalidRequest`]: ../http/enum.HttpError.html#variant.InvalidRequest
- pub fn invite_url(&self, permissions: Permissions) -> FutureResult<String> {
- let bits = permissions.bits();
-
- let done = ftryopt!(self.client)
- .http
- .get_current_application_info()
- .map(move |app| {
- let mut url = format!(
- "https://discordapp.com/api/oauth2/authorize?client_id={}&scope=bot",
- app.id,
- );
-
- if bits != 0 {
- let _ = write!(url, "&permissions={}", bits);
- }
-
- url
- });
-
- Box::new(done)
- }
-
/// Returns a static formatted URL of the user's icon, if one exists.
///
/// This will always produce a WEBP image URL.
@@ -356,8 +197,6 @@ pub struct User {
/// change if the username+discriminator pair becomes non-unique.
#[serde(rename = "username")]
pub name: String,
- #[serde(skip)]
- pub(crate) client: WrappedClient,
}
use std::hash::{Hash, Hasher};
@@ -376,7 +215,6 @@ impl Hash for User {
}
}
-#[cfg(feature = "model")]
impl User {
/// Returns the formatted URL of the user's icon, if one exists.
///
@@ -384,15 +222,6 @@ impl User {
#[inline]
pub fn avatar_url(&self) -> Option<String> { avatar_url(self.id, self.avatar.as_ref()) }
- /// Creates a direct message channel between the [current user] and the
- /// user. This can also retrieve the channel if one already exists.
- ///
- /// [current user]: struct.CurrentUser.html
- #[inline]
- pub fn create_dm_channel(&self) -> FutureResult<PrivateChannel> {
- ftryopt!(self.client).http.create_private_channel(self.id.0)
- }
-
/// Retrieves the time that this user was created at.
#[inline]
pub fn created_at(&self) -> NaiveDateTime { self.id.created_at() }
@@ -403,163 +232,6 @@ impl User {
#[inline]
pub fn default_avatar_url(&self) -> String { default_avatar_url(self.discriminator) }
- /// Sends a message to a user through a direct message channel. This is a
- /// channel that can only be accessed by you and the recipient.
- ///
- /// # Examples
- ///
- /// When a user sends a message with a content of `"~help"`, DM the author a
- /// help message, and then react with `'👌'` to verify message sending:
- ///
- /// ```rust,no_run
- /// # use serenity::prelude::*;
- /// # use serenity::model::prelude::*;
- /// #
- /// use serenity::model::Permissions;
- /// use serenity::CACHE;
- ///
- /// struct Handler;
- ///
- /// impl EventHandler for Handler {
- /// fn message(&self, _: Context, msg: Message) {
- /// if msg.content == "~help" {
- /// let cache = CACHE.read();
- ///
- /// let url = match cache.user.invite_url(Permissions::empty()) {
- /// Ok(v) => v,
- /// Err(why) => {
- /// println!("Error creating invite url: {:?}", why);
- ///
- /// return;
- /// },
- /// };
- ///
- /// let help = format!(
- /// "Helpful info here. Invite me with this link: <{}>",
- /// url,
- /// );
- ///
- /// match msg.author.direct_message(|m| m.content(&help)) {
- /// Ok(_) => {
- /// let _ = msg.react('👌');
- /// },
- /// Err(why) => {
- /// println!("Err sending help: {:?}", why);
- ///
- /// let _ = msg.reply("There was an error DMing you help.");
- /// },
- /// };
- /// }
- /// }
- /// }
- ///
- /// let mut client = Client::new("token", Handler);
- /// ```
- ///
- /// # Examples
- ///
- /// Returns a [`ModelError::MessagingBot`] if the user being direct messaged
- /// is a bot user.
- ///
- /// [`ModelError::MessagingBot`]: enum.ModelError.html#variant.MessagingBot
- /// [`PrivateChannel`]: struct.PrivateChannel.html
- /// [`User::dm`]: struct.User.html#method.dm
- // A tale with Clippy:
- //
- // A person named Clippy once asked you to unlock a box and take something
- // from it, but you never re-locked it, so you'll die and the universe will
- // implode because the box must remain locked unless you're there, and you
- // can't just borrow that item from it and take it with you forever.
- //
- // Instead what you do is unlock the box, take the item out of it, make a
- // copy of said item, and then re-lock the box, and take your copy of the
- // item with you.
- //
- // The universe is still fine, and nothing implodes.
- //
- // (AKA: Clippy is wrong and so we have to mark as allowing this lint.)
- #[allow(let_and_return)]
- #[cfg(feature = "builder")]
- pub fn direct_message<'a, F: 'a + FnOnce(CreateMessage) -> CreateMessage>(
- &'a self,
- f: F,
- ) -> Box<Future<Item = Message, Error = Error> + 'a> {
- if self.bot {
- return Box::new(future::err(Error::Model(
- ModelError::MessagingBot,
- )));
- }
-
- let client = ftryopt!(self.client);
-
- let private_channel_id = feature_cache! {{
- let finding = {
- let cache = client.cache.borrow();
-
- let finding = cache.private_channels
- .values()
- .find(|ch| {
- let ch = ch.borrow();
- let recipient = ch.recipient.borrow();
-
- recipient.id == self.id
- })
- .map(|ch| ch.borrow().id);
-
- finding
- };
-
- if let Some(finding) = finding {
- return Box::new(client.http.send_message(finding.0, f));
- } else {
- let done = client
- .http
- .create_private_channel(self.id.0)
- .map(|channel| channel.id);
-
- Box::new(done)
- }
- } else {
- let done = ftryopt!(self.client)
- .http
- .create_private_channel(self.id.0)
- .map(|channel| channel.id);
-
- Box::new(done)
- }};
-
- Box::new(private_channel_id
- .and_then(move |id| client.http.send_message(id.0, f)))
- }
-
- /// This is an alias of [direct_message].
- ///
- /// # Examples
- ///
- /// Sending a message:
- ///
- /// ```rust,ignore
- /// // assuming you are in a context
- ///
- /// let _ = message.author.dm("Hello!");
- /// ```
- ///
- /// # Examples
- ///
- /// Returns a [`ModelError::MessagingBot`] if the user being direct messaged
- /// is a bot user.
- ///
- /// [`ModelError::MessagingBot`]: enum.ModelError.html#variant.MessagingBot
- /// [direct_message]: #method.direct_message
- #[cfg(feature = "builder")]
- #[inline]
- pub fn dm<'a, F: 'a + FnOnce(CreateMessage) -> CreateMessage>(
- &'a self,
- f: F,
- ) -> Box<Future<Item = Message, Error = Error> + 'a> {
- self.direct_message(f)
- }
-
/// Retrieves the URL to the user's avatar, falling back to the default
/// avatar if needed.
///
@@ -573,59 +245,6 @@ impl User {
.unwrap_or_else(|| self.default_avatar_url())
}
- /// Check if a user has a [`Role`]. This will retrieve the [`Guild`] from
- /// the [`Cache`] if it is available, and then check if that guild has the
- /// given [`Role`].
- ///
- /// Three forms of data may be passed in to the guild parameter: either a
- /// [`PartialGuild`], a [`GuildId`], or a `u64`.
- ///
- /// # Examples
- ///
- /// Check if a guild has a [`Role`] by Id:
- ///
- /// ```rust,ignore
- /// // Assumes a 'guild_id' and `role_id` have already been bound
- /// let _ = message.author.has_role(guild_id, role_id);
- /// ```
- ///
- /// [`Guild`]: struct.Guild.html
- /// [`GuildId`]: struct.GuildId.html
- /// [`PartialGuild`]: struct.PartialGuild.html
- /// [`Role`]: struct.Role.html
- /// [`Cache`]: ../cache/struct.Cache.html
- // no-cache would warn on guild_id.
- pub fn has_role<G, R>(&self, guild: G, role: R) -> bool
- where G: Into<GuildContainer>, R: Into<RoleId> {
- let role_id = role.into();
-
- match guild.into() {
- GuildContainer::Guild(guild) => guild.roles.contains_key(&role_id),
- GuildContainer::Id(_guild_id) => {
- feature_cache! {{
- let client = match self.client.as_ref() {
- Some(client) => client,
- None => return false,
- };
-
- let cache = client.cache.borrow();
-
- cache
- .guilds
- .get(&_guild_id)
- .map(|g| {
- g.borrow().members.get(&self.id)
- .map(|m| m.borrow().roles.contains(&role_id))
- .unwrap_or(false)
- })
- .unwrap_or(false)
- } else {
- true
- }}
- },
- }
- }
-
/// Returns a static formatted URL of the user's icon, if one exists.
///
/// This will always produce a WEBP image URL.
@@ -699,7 +318,6 @@ impl<'a> From<&'a User> for UserId {
fn from(user: &User) -> UserId { user.id }
}
-#[cfg(feature = "model")]
fn avatar_url(user_id: UserId, hash: Option<&String>) -> Option<String> {
hash.map(|hash| {
let ext = if hash.starts_with("a_") {
@@ -712,17 +330,14 @@ fn avatar_url(user_id: UserId, hash: Option<&String>) -> Option<String> {
})
}
-#[cfg(feature = "model")]
fn default_avatar_url(discriminator: u16) -> String {
cdn!("/embed/avatars/{}.png", discriminator % 5u16)
}
-#[cfg(feature = "model")]
fn static_avatar_url(user_id: UserId, hash: Option<&String>) -> Option<String> {
hash.map(|hash| cdn!("/avatars/{}/{}.webp?size=1024", user_id, hash))
}
-#[cfg(feature = "model")]
fn tag(name: &str, discriminator: u16) -> String {
// 32: max length of username
// 1: `#`
diff --git a/src/model/utils.rs b/src/model/utils.rs
index 9ed34e1..f18f19a 100644
--- a/src/model/utils.rs
+++ b/src/model/utils.rs
@@ -258,17 +258,6 @@ impl PermissionCheck for Cache {
}
}
-macro_rules! ftryopt {
- ($code:expr) => {
- match $code {
- Some(ref v) => v,
- None => return Box::new(::futures::future::err(::Error::Model(
- ::model::ModelError::ClientNotPresent,
- ))),
- }
- };
-}
-
macro_rules! num_visitors {
($($visitor:ident: $type:ty),*) => {
$(
diff --git a/src/model/webhook.rs b/src/model/webhook.rs
index f3003e7..9bd374a 100644
--- a/src/model/webhook.rs
+++ b/src/model/webhook.rs
@@ -1,17 +1,7 @@
//! Webhook model and implementations.
-use futures::Future;
use super::id::{ChannelId, GuildId, WebhookId};
use super::user::User;
-use super::WrappedClient;
-use ::FutureResult;
-
-#[cfg(feature = "model")]
-use builder::ExecuteWebhook;
-#[cfg(feature = "model")]
-use internal::prelude::*;
-#[cfg(feature = "model")]
-use super::channel::Message;
/// A representation of a webhook, which is a low-effort way to post messages to
/// channels. They do not necessarily require a bot user or authentication to
@@ -44,139 +34,4 @@ pub struct Webhook {
///
/// **Note**: This is not received when getting a webhook by its token.
pub user: Option<User>,
- #[serde(skip)]
- pub(crate) client: WrappedClient,
-}
-
-#[cfg(feature = "model")]
-impl Webhook {
- /// Deletes the webhook.
- ///
- /// As this calls the [`http::delete_webhook_with_token`] function,
- /// authentication is not required.
- ///
- /// [`http::delete_webhook_with_token`]: ../http/fn.delete_webhook_with_token.html
- #[inline]
- pub fn delete(&self) -> FutureResult<()> {
- let done = ftryopt!(self.client)
- .http
- .delete_webhook_with_token(self.id.0, &self.token);
-
- Box::new(done)
- }
-
- ///
- /// Edits the webhook in-place. All fields are optional.
- ///
- /// To nullify the avatar, pass `Some("")`. Otherwise, passing `None` will
- /// not modify the avatar.
- ///
- /// Refer to [`http::edit_webhook`] for httprictions on editing webhooks.
- ///
- /// As this calls the [`http::edit_webhook_with_token`] function,
- /// authentication is not required.
- ///
- /// # Examples
- ///
- /// Editing a webhook's name:
- ///
- /// ```rust,no_run
- /// use serenity::http;
- ///
- /// let id = 245037420704169985;
- /// let token = "ig5AO-wdVWpCBtUUMxmgsWryqgsW3DChbKYOINftJ4DCrUbnkedoYZD0VOH1QLr-S3sV";
- ///
- /// let mut webhook = http::get_webhook_with_token(id, token)
- /// .expect("valid webhook");
- ///
- /// let _ = webhook.edit(Some("new name"), None).expect("Error editing");
- /// ```
- ///
- /// Setting a webhook's avatar:
- ///
- /// ```rust,no_run
- /// use serenity::http;
- ///
- /// let id = 245037420704169985;
- /// let token = "ig5AO-wdVWpCBtUUMxmgsWryqgsW3DChbKYOINftJ4DCrUbnkedoYZD0VOH1QLr-S3sV";
- ///
- /// let mut webhook = http::get_webhook_with_token(id, token)
- /// .expect("valid webhook");
- ///
- /// let image = serenity::utils::read_image("./webhook_img.png")
- /// .expect("Error reading image");
- ///
- /// let _ = webhook.edit(None, Some(&image)).expect("Error editing");
- /// ```
- ///
- /// [`http::edit_webhook`]: ../http/fn.edit_webhook.html
- /// [`http::edit_webhook_with_token`]: ../http/fn.edit_webhook_with_token.html
- pub fn edit(&mut self, name: Option<&str>, avatar: Option<&str>)
- -> Box<Future<Item = Webhook, Error = Error>> {
- let done = ftryopt!(self.client)
- .http
- .edit_webhook_with_token(self.id.0, &self.token, name, avatar);
-
- Box::new(done)
- }
-
- /// Executes a webhook with the fields set via the given builder.
- ///
- /// The builder provides a method of setting only the fields you need,
- /// without needing to pass a long set of arguments.
- ///
- /// # Examples
- ///
- /// Execute a webhook with message content of `test`:
- ///
- /// ```rust,no_run
- /// use serenity::http;
- ///
- /// let id = 245037420704169985;
- /// let token = "ig5AO-wdVWpCBtUUMxmgsWryqgsW3DChbKYOINftJ4DCrUbnkedoYZD0VOH1QLr-S3sV";
- ///
- /// let mut webhook = http::get_webhook_with_token(id, token)
- /// .expect("valid webhook");
- ///
- /// let _ = webhook.execute(false, |w| w.content("test")).expect("Error executing");
- /// ```
- ///
- /// Execute a webhook with message content of `test`, overriding the
- /// username to `serenity`, and sending an embed:
- ///
- /// ```rust,no_run
- /// use serenity::http;
- /// use serenity::model::channel::Embed;
- ///
- /// let id = 245037420704169985;
- /// let token = "ig5AO-wdVWpCBtUUMxmgsWryqgsW3DChbKYOINftJ4DCrUbnkedoYZD0VOH1QLr-S3sV";
- ///
- /// let mut webhook = http::get_webhook_with_token(id, token)
- /// .expect("valid webhook");
- ///
- /// let embed = Embed::fake(|e| e
- /// .title("Rust's website")
- /// .description("Rust is a systems programming language that runs
- /// blazingly fast, prevents segfaults, and guarantees
- /// thread safety.")
- /// .url("https://rust-lang.org"));
- ///
- /// let _ = webhook.execute(false, |w| w
- /// .content("test")
- /// .username("serenity")
- /// .embeds(vec![embed]))
- /// .expect("Error executing");
- /// ```
- #[inline]
- pub fn execute<'a, F: FnOnce(ExecuteWebhook) -> ExecuteWebhook>(
- &'a self,
- wait: bool,
- f: F,
- ) -> Box<Future<Item = Option<Message>, Error = Error> + 'a> {
- let done = ftryopt!(self.client)
- .http
- .execute_webhook(self.id.0, &self.token, wait, f);
-
- Box::new(done)
- }
}