aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAustin Hellyer <[email protected]>2017-01-23 12:16:06 -0800
committerAustin Hellyer <[email protected]>2017-01-23 12:16:06 -0800
commit651c618f17cb92d3ea9bbd1d5f5c92a015ff64e0 (patch)
treedcf452e8fe73411af331678a769cb769a32dd12e /src
parentFix no-framework compilation (diff)
downloadserenity-651c618f17cb92d3ea9bbd1d5f5c92a015ff64e0.tar.xz
serenity-651c618f17cb92d3ea9bbd1d5f5c92a015ff64e0.zip
Switch to a mostly-fully OOP approach
The context is now strictly in relation to the context of the current channel related to the event, if any. See Context::say for a list of events that the context can be used for.
Diffstat (limited to 'src')
-rw-r--r--src/client/context.rs1406
-rw-r--r--src/client/rest/mod.rs3
-rw-r--r--src/ext/framework/help_commands.rs21
-rw-r--r--src/ext/framework/mod.rs2
-rw-r--r--src/model/channel.rs1363
-rw-r--r--src/model/gateway.rs2
-rw-r--r--src/model/guild.rs1718
-rw-r--r--src/model/id.rs238
-rw-r--r--src/model/invite.rs59
-rw-r--r--src/model/misc.rs7
-rw-r--r--src/model/mod.rs12
-rw-r--r--src/model/user.rs214
-rw-r--r--src/model/utils.rs8
-rw-r--r--src/model/webhook.rs31
-rw-r--r--src/utils/macros.rs19
15 files changed, 3262 insertions, 1841 deletions
diff --git a/src/client/context.rs b/src/client/context.rs
index 73882dd..aa33e5f 100644
--- a/src/client/context.rs
+++ b/src/client/context.rs
@@ -1,6 +1,4 @@
use serde_json::builder::ObjectBuilder;
-use std::collections::HashMap;
-use std::fmt::Write as FmtWrite;
use std::io::Read;
use std::sync::{Arc, Mutex};
use super::gateway::Shard;
@@ -9,19 +7,13 @@ use super::login_type::LoginType;
use typemap::ShareMap;
use ::utils::builder::{
CreateEmbed,
- CreateInvite,
CreateMessage,
EditChannel,
- EditGuild,
- EditMember,
EditProfile,
- EditRole,
- GetMessages,
Search,
};
use ::internal::prelude::*;
use ::model::*;
-use ::utils;
#[cfg(feature="extras")]
use std::ops::ShlAssign;
@@ -90,7 +82,7 @@ pub struct Context {
/// A clone of [`Client::data`]. Refer to its documentation for more
/// information.
///
- /// [`Client::data`]: struct.Client.html#method.data
+ /// [`Client::data`]: struct.Client.html#structfield.data
pub data: Arc<Mutex<ShareMap>>,
/// The associated shard which dispatched the event handler.
///
@@ -124,29 +116,7 @@ impl Context {
}
}
- /// Accepts the given invite.
- ///
- /// Refer to the documentation for [`rest::accept_invite`] for restrictions
- /// on accepting an invite.
- ///
- /// **Note**: Requires that the current user be a user account.
- ///
- /// # Errors
- ///
- /// Returns a [`ClientError::InvalidOperationAsBot`] if the current user is
- /// a bot user.
- ///
- /// [`ClientError::InvalidOperationAsBot`]: enum.ClientError.html#variant.InvalidOperationAsBot
- /// [`rest::accept_invite`]: rest/fn.accept_invite.html
- pub fn accept_invite(&self, invite: &str) -> Result<Invite> {
- if self.login_type == LoginType::Bot {
- return Err(Error::Client(ClientError::InvalidOperationAsBot));
- }
-
- rest::accept_invite(utils::parse_invite(invite))
- }
-
- /// Marks a [`Channel`] as being read up to a certain [`Message`].
+ /// Marks the contextual channel as being read up to a certain [`Message`].
///
/// Refer to the documentation for [`rest::ack_message`] for more
/// information.
@@ -156,52 +126,25 @@ impl Context {
/// Returns a [`ClientError::InvalidOperationAsBot`] if the current user is
/// a bot user.
///
- /// [`Channel`]: ../../model/enum.Channel.html
- /// [`ClientError::InvalidOperationAsBot`]: ../enum.ClientError.html#variant.InvalidOperationAsUser
- /// [`Message`]: ../../model/struct.Message.html
+ /// Returns a [`ClientError::NoChannelId`] if the current context is not
+ /// related to a channel.
+ ///
+ /// [`Channel`]: ../model/enum.Channel.html
+ /// [`ChannelId`]: ../model/struct.ChannelId.html
+ /// [`ClientError::InvalidOperationAsBot`]: enum.ClientError.html#variant.InvalidOperationAsUser
+ /// [`ClientError::NoChannelId`]: enum.ClientError.html#variant.NoChannelId
+ /// [`Message`]: ../model/struct.Message.html
/// [`rest::ack_message`]: rest/fn.ack_message.html
- pub fn ack<C, M>(&self, channel_id: C, message_id: M) -> Result<()>
- where C: Into<ChannelId>, M: Into<MessageId> {
+ /// [`say`]: #method.say
+ pub fn ack<M: Into<MessageId>>(&self, message_id: M) -> Result<()> {
if self.login_type == LoginType::User {
return Err(Error::Client(ClientError::InvalidOperationAsUser));
}
- rest::ack_message(channel_id.into().0, message_id.into().0)
- }
-
- /// Bans a [`User`] from a [`Guild`], removing their messages sent in the
- /// last X number of days.
- ///
- /// Refer to the documentation for [`rest::ban_user`] for more information.
- ///
- /// Requires the [Ban Members] permission.
- ///
- /// # Examples
- ///
- /// Ban the user that sent a message for `7` days:
- ///
- /// ```rust,ignore
- /// // assuming you are in a context
- /// context.ban_user(context.guild_id, context.message.author, 7);
- /// ```
- ///
- /// # Errors
- ///
- /// Returns a [`ClientError::DeleteMessageDaysAmount`] if the number of days
- /// given is over the maximum allowed.
- ///
- /// [`ClientError::DeleteMessageDaysAmount`]: enum.ClientError.html#variant.DeleteMessageDaysAmount
- /// [`Guild`]: ../model/struct.Guild.html
- /// [`User`]: ../model/struct.User.html
- /// [`rest::ban_user`]: rest/fn.ban_user.html
- /// [Ban Members]: ../model/permissions/constant.BAN_MEMBERS.html
- pub fn ban<G, U>(&self, guild_id: G, user_id: U, delete_message_days: u8)
- -> Result<()> where G: Into<GuildId>, U: Into<UserId> {
- if delete_message_days > 7 {
- return Err(Error::Client(ClientError::DeleteMessageDaysAmount(delete_message_days)));
+ match self.channel_id {
+ Some(channel_id) => channel_id.ack(message_id),
+ None => Err(Error::Client(ClientError::NoChannelId)),
}
-
- rest::ban_user(guild_id.into().0, user_id.into().0, delete_message_days)
}
/// Broadcasts that you are typing to a channel for the next 5 seconds.
@@ -221,244 +164,55 @@ impl Context {
/// context.broadcast_typing(context.channel_id);
/// ```
///
- /// [Send Messages]: ../model/permissions/constant.SEND_MESSAGES.html
- pub fn broadcast_typing<C>(&self, channel_id: C) -> Result<()>
- where C: Into<ChannelId> {
- rest::broadcast_typing(channel_id.into().0)
- }
-
- /// Creates a [`GuildChannel`] in the given [`Guild`].
- ///
- /// Refer to [`rest::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;
- ///
- /// context.create_channel(context.guild_id, "test", ChannelType::Voice);
- /// ```
- ///
- /// [`Guild`]: ../model/struct.Guild.html
- /// [`GuildChannel`]: ../model/struct.GuildChannel.html
- /// [`rest::create_channel`]: rest/fn.create_channel.html
- /// [Manage Channels]: ../model/permissions/constant.MANAGE_CHANNELS.html
- pub fn create_channel<G>(&self, guild_id: G, name: &str, kind: ChannelType)
- -> Result<Channel> where G: Into<GuildId> {
- let map = ObjectBuilder::new()
- .insert("name", name)
- .insert("type", kind.name())
- .build();
-
- rest::create_channel(guild_id.into().0, map)
- }
-
- /// Creates an emoji in the given 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`]: ../utils/builder/struct.EditProfile.html#method.avatar
- /// [`utils::read_image`]: ../utils/fn.read_image.html
- /// [Manage Emojis]: ../model/permissions/constant.MANAGE_EMOJIS.html
- pub fn create_emoji<G>(&self, guild_id: G, name: &str, image: &str)
- -> Result<Emoji> where G: Into<GuildId> {
- let map = ObjectBuilder::new()
- .insert("name", name)
- .insert("image", image)
- .build();
-
- rest::create_emoji(guild_id.into().0, map)
- }
-
- /// Creates a guild with the data provided.
- ///
- /// Only a [`PartialGuild`] will be immediately returned, and a full
- /// [`Guild`] will be received over a [`Shard`].
- ///
- /// **Note**: This endpoint is usually only available for user accounts.
- /// Refer to Discord's information for the endpoint [here][whitelist] for
- /// more information. If you require this as a bot, re-think what you are
- /// doing and if it _really_ needs to be doing this.
- ///
- /// # Examples
- ///
- /// Create a guild called `"test"` in the [US West region] with no icon:
- ///
- /// ```rust,ignore
- /// use serenity::model::Region;
- ///
- /// context.create_guild("test", Region::UsWest, None);
- /// ```
- ///
- /// [`Guild`]: ../model/struct.Guild.html
- /// [`PartialGuild`]: ../model/struct.PartialGuild.html
- /// [`Shard`]: ../gateway/struct.Shard.html
- /// [US West region]: ../model/enum.Region.html#variant.UsWest
- /// [whitelist]: https://discordapp.com/developers/docs/resources/guild#create-guild
- pub fn create_guild(&self, name: &str, region: Region, icon: Option<&str>)
- -> Result<PartialGuild> {
- let map = ObjectBuilder::new()
- .insert("icon", icon)
- .insert("name", name)
- .insert("region", region.name())
- .build();
-
- rest::create_guild(map)
- }
-
- /// Creates an [`Integration`] for a [`Guild`].
- ///
- /// Requires the [Manage Guild] permission.
- ///
- /// [`Guild`]: ../model/struct.Guild.html
- /// [`Integration`]: ../model/struct.Integration.html
- /// [Manage Guild]: ../model/permissions/constant.MANAGE_GUILD.html
- pub fn create_integration<G, I>(&self,
- guild_id: G,
- integration_id: I,
- kind: &str)
- -> Result<()> where G: Into<GuildId>,
- I: Into<IntegrationId> {
- let integration_id = integration_id.into();
- let map = ObjectBuilder::new()
- .insert("id", integration_id.0)
- .insert("type", kind)
- .build();
-
- rest::create_guild_integration(guild_id.into().0, integration_id.0, map)
- }
-
- /// Creates an invite for the channel, providing a builder so that fields
- /// may optionally be set.
+ /// # Errors
///
- /// See the documentation for the [`CreateInvite`] builder for information
- /// on how to use this and the default values that it provides.
+ /// Returns a [`ClientError::InvalidOperationAsBot`] if the current user is
+ /// a bot user.
///
- /// Requires the [Create Invite] permission.
+ /// Returns a [`ClientError::NoChannelId`] if the current context is not
+ /// related to a channel.
///
- /// [`CreateInvite`]: ../utils/builder/struct.CreateInvite.html
- /// [Create Invite]: ../model/permissions/constant.CREATE_INVITE.html
- pub fn create_invite<C, F>(&self, channel_id: C, f: F) -> Result<RichInvite>
- where C: Into<ChannelId>, F: FnOnce(CreateInvite) -> CreateInvite {
- let map = f(CreateInvite::default()).0.build();
+ /// [`ChannelId`]: ../model/struct.ChannelId.html
+ /// [`ClientError::InvalidOperationAsBot`]: enum.ClientError.html#variant.InvalidOperationAsUser
+ /// [`ClientError::NoChannelId`]: enum.ClientError.html#variant.NoChannelId
+ /// [`say`]: #method.say
+ /// [Send Messages]: ../model/permissions/constant.SEND_MESSAGES.html
+ pub fn broadcast_typing(&self) -> Result<()> {
+ if self.login_type == LoginType::User {
+ return Err(Error::Client(ClientError::InvalidOperationAsUser));
+ }
- rest::create_invite(channel_id.into().0, map)
+ match self.channel_id {
+ Some(channel_id) => channel_id.broadcast_typing(),
+ None => Err(Error::Client(ClientError::NoChannelId)),
+ }
}
/// Creates a [permission overwrite][`PermissionOverwrite`] for either a
- /// single [`Member`] or [`Role`] within a [`Channel`].
+ /// single [`Member`] or [`Role`] within the channel.
///
- /// Refer to the documentation for [`PermissionOverwrite`]s for more
- /// information.
+ /// Refer to the documentation for [`GuildChannel::create_permission`] for
+ /// more information.
///
/// Requires the [Manage Channels] permission.
///
- /// # Examples
- ///
- /// Creating a permission overwrite for a member by specifying the
- /// [`PermissionOverwrite::Member`] variant, allowing it the [Send Messages]
- /// permission, but denying the [Send TTS Messages] and [Attach Files]
- /// permissions:
- ///
- /// ```rust,ignore
- /// use serenity::model::{ChannelId, PermissionOverwrite, permissions};
- ///
- /// // assuming you are in a context
- ///
- /// let channel_id = 7;
- /// let user_id = 8;
- ///
- /// let allow = permissions::SEND_MESSAGES;
- /// let deny = permissions::SEND_TTS_MESSAGES | permissions::ATTACH_FILES;
- /// let overwrite = PermissionOverwrite {
- /// allow: allow,
- /// deny: deny,
- /// kind: PermissionOverwriteType::Member(user_id),
- /// };
- ///
- /// let _result = context.create_permission(channel_id, overwrite);
- /// ```
- ///
- /// Creating a permission overwrite for a role by specifying the
- /// [`PermissionOverwrite::Role`] variant, allowing it the [Manage Webhooks]
- /// permission, but denying the [Send TTS Messages] and [Attach Files]
- /// permissions:
- ///
- /// ```rust,ignore
- /// use serenity::model::{ChannelId, PermissionOverwrite, permissions};
- ///
- /// // assuming you are in a context
- ///
- /// let channel_id = 7;
- /// let user_id = 8;
- ///
- /// let allow = permissions::SEND_MESSAGES;
- /// let deny = permissions::SEND_TTS_MESSAGES | permissions::ATTACH_FILES;
- /// let overwrite = PermissionOverwrite {
- /// allow: allow,
- /// deny: deny,
- /// kind: PermissionOverwriteType::Member(user_id),
- /// };
+ /// # Errors
///
- /// let _result = context.create_permission(channel_id, overwrite);
- /// ```
+ /// Returns a [`ClientError::NoChannelId`] if the current context is not
+ /// related to a channel.
///
- /// [`Channel`]: ../model/enum.Channel.html
+ /// [`ClientError::NoChannelId`]: enum.ClientError.html#variant.NoChannelId
+ /// [`GuildChannel::create_permission`]: struct.GuildChannel.html#method.create_permission
/// [`Member`]: ../model/struct.Member.html
/// [`PermissionOverwrite`]: ../model/struct.PermissionOverWrite.html
- /// [`PermissionOverwrite::Member`]: ../model/struct.PermissionOverwrite.html#variant.Member
/// [`Role`]: ../model/struct.Role.html
- /// [Attach Files]: ../model/permissions/constant.ATTACH_FILES.html
/// [Manage Channels]: ../model/permissions/constant.MANAGE_CHANNELS.html
- /// [Manage Webhooks]: ../model/permissions/constant.MANAGE_WEBHOOKS.html
- /// [Send TTS Messages]: ../model/permissions/constant.SEND_TTS_MESSAGES.html
- pub fn create_permission<C>(&self,
- channel_id: C,
- target: PermissionOverwrite)
- -> Result<()> where C: Into<ChannelId> {
- let (id, kind) = match target.kind {
- PermissionOverwriteType::Member(id) => (id.0, "member"),
- PermissionOverwriteType::Role(id) => (id.0, "role"),
- };
-
- let map = ObjectBuilder::new()
- .insert("allow", target.allow.bits())
- .insert("deny", target.deny.bits())
- .insert("id", id)
- .insert("type", kind)
- .build();
-
- rest::create_permission(channel_id.into().0, id, map)
- }
-
- /// Creates a direct message channel between the [current user] and another
- /// [`User`]. This can also retrieve the channel if one already exists.
- ///
- /// [`User`]: ../model/struct.User.html
- /// [current user]: ../model/struct.CurrentUser.html
- pub fn create_direct_message_channel<U>(&self, user_id: U)
- -> Result<PrivateChannel> where U: Into<UserId> {
- let map = ObjectBuilder::new()
- .insert("recipient_id", user_id.into().0)
- .build();
-
- rest::create_private_channel(map)
+ pub fn create_permission(&self, target: PermissionOverwrite)
+ -> Result<()> {
+ match self.channel_id {
+ Some(channel_id) => channel_id.create_permission(target),
+ None => Err(Error::Client(ClientError::NoChannelId)),
+ }
}
/// React to a [`Message`] with a custom [`Emoji`] or unicode character.
@@ -469,118 +223,49 @@ impl Context {
/// Requires the [Add Reactions] permission, _if_ the current user is the
/// first user to perform a react with a certain emoji.
///
+ /// # Errors
+ ///
+ /// Returns a [`ClientError::NoChannelId`] if the current context is not
+ /// related to a channel.
+ ///
+ /// [`ClientError::NoChannelId`]: enum.ClientError.html#variant.NoChannelId
/// [`Emoji`]: ../model/struct.Emoji.html
/// [`Message`]: ../model/struct.Message.html
/// [`Message::react`]: ../model/struct.Message.html#method.react
/// [Add Reactions]: ../model/permissions/constant.ADD_REACTIONS.html
- pub fn create_reaction<C, M, R>(&self,
- channel_id: C,
- message_id: M,
- reaction_type: R)
- -> Result<()>
- where C: Into<ChannelId>,
- M: Into<MessageId>,
- R: Into<ReactionType> {
- rest::create_reaction(channel_id.into().0,
- message_id.into().0,
- reaction_type.into())
- }
-
- /// Creates a [`Role`] in guild with given Id. Second argument is a
- /// closure, and you can use it to automatically configure role.
- ///
- /// Requires the [Manage Roles] permission.
- ///
- /// # Examples
- ///
- /// Create a role which can be mentioned, with the name 'test':
- ///
- /// ```rust,ignore
- /// let role = context.create_role(guild_id, |r| r
- /// .hoist(true)
- /// .name("role"));
- /// ```
- ///
- /// [`Role`]: ../model/struct.Role.html
- /// [Manage Roles]: ../model/permissions/constant.MANAGE_ROLES.html
- pub fn create_role<F, G>(&self, guild_id: G, f: F) -> Result<Role>
- where F: FnOnce(EditRole) -> EditRole, G: Into<GuildId> {
- rest::create_role(guild_id.into().0, f(EditRole::default()).0.build())
+ pub fn create_reaction<M, R>(&self, message_id: M, reaction_type: R)
+ -> Result<()> where M: Into<MessageId>, R: Into<ReactionType> {
+ match self.channel_id {
+ Some(channel_id) => channel_id.create_reaction(message_id, reaction_type),
+ None => Err(Error::Client(ClientError::NoChannelId)),
+ }
}
- /// Deletes a [`Channel`] based on the Id given.
+ /// Deletes the contextual channel.
///
/// If the channel being deleted is a [`GuildChannel`] (a [`Guild`]'s
/// channel), then the [Manage Channels] permission is required.
///
+ /// # Errors
+ ///
+ /// Returns a [`ClientError::NoChannelId`] if the current context is not
+ /// related to a channel.
+ ///
/// [`Channel`]: ../model/enum.Channel.html
+ /// [`ClientError::NoChannelId`]: enum.ClientError.html#variant.NoChannelId
/// [`Guild`]: ../model/struct.Guild.html
/// [`GuildChannel`]: ../model/struct.GuildChannel.html
/// [Manage Channels]: ../model/permissions/constant.MANAGE_CHANNELS.html
- pub fn delete_channel<C>(&self, channel_id: C) -> Result<Channel>
- where C: Into<ChannelId> {
- rest::delete_channel(channel_id.into().0)
- }
-
- /// Deletes an emoji in a [`Guild`] given its Id.
- ///
- /// Requires the [Manage Emojis] permission.
- ///
- /// [`Guild`]: ../model/struct.Guild.html
- /// [Manage Emojis]: ../model/permissions/constant.MANAGE_EMOJIS.html
- pub fn delete_emoji<E, G>(&self, guild_id: G, emoji_id: E) -> Result<()>
- where E: Into<EmojiId>, G: Into<GuildId> {
- rest::delete_emoji(guild_id.into().0, emoji_id.into().0)
- }
-
- /// Deletes a [`Guild`]. The current user must be the guild owner to be able
- /// to delete it.
- ///
- /// Only a [`PartialGuild`] will be immediately returned.
- ///
- /// [`Guild`]: ../model/struct.Guild.html
- /// [`PartialGuild`]: ../model/struct.PartialGuild.html
- pub fn delete_guild<G: Into<GuildId>>(&self, guild_id: G)
- -> Result<PartialGuild> {
- rest::delete_guild(guild_id.into().0)
- }
-
- /// Deletes an integration by Id from a guild which Id was given.
- ///
- /// Requires the [Manage Guild] permission.
- ///
- /// [Manage Guild]: ../model/permissions/constant.MANAGE_GUILD.html
- pub fn delete_integration<G, I>(&self, guild_id: G, integration_id: I)
- -> Result<()> where G: Into<GuildId>, I: Into<IntegrationId> {
- rest::delete_guild_integration(guild_id.into().0,
- integration_id.into().0)
- }
-
- /// Deletes the given invite.
- ///
- /// Refer to the documentation for [`Invite::delete`] for restrictions on
- /// deleting an invite.
- ///
- /// Requires the [Manage Guild] permission.
- ///
- /// # Errors
- ///
- /// Returns a [`ClientError::InvalidPermissions`] if the current user does
- /// not have the required [permission].
- ///
- /// [`ClientError::InvalidPermissions`]: ../client/enum.ClientError.html#variant.InvalidPermissions
- /// [`Invite::delete`]: ../model/struct.Invite.html#method.delete
- /// [Manage Guild]: permissions/constant.MANAGE_GUILD.html
- pub fn delete_invite(&self, invite: &str) -> Result<Invite> {
- rest::delete_invite(utils::parse_invite(invite))
+ pub fn delete_channel(&self) -> Result<Channel> {
+ match self.channel_id {
+ Some(channel_id) => channel_id.delete(),
+ None => Err(Error::Client(ClientError::NoChannelId)),
+ }
}
- /// Deletes a [`Message`] given its Id.
+ /// Deletes a [`Message`] given its Id from the contextual channel.
///
- /// Also see [`Message::delete`] if you have the `methods` feature enabled.
- ///
- /// Requires the [Manage Messages] permission, if the current user is not
- /// the author of the message.
+ /// Refer to [`Message::delete`] for more information.
///
/// # Examples
///
@@ -591,19 +276,27 @@ impl Context {
/// use std::env;
///
/// let client = Client::login_bot(&env::var("DISCORD_BOT_TOKEN").unwrap());
- /// client.on_message(|context, message| {
- /// context.delete_message(message);
+ /// client.on_message(|ctx, message| {
+ /// ctx.delete_message(message);
/// });
/// ```
///
/// (in practice, please do not do this)
///
+ /// # Errors
+ ///
+ /// Returns a [`ClientError::NoChannelId`] if the current context is not
+ /// related to a channel.
+ ///
+ /// [`ClientError::NoChannelId`]: enum.ClientError.html#variant.NoChannelId
/// [`Message`]: ../model/struct.Message.html
/// [`Message::delete`]: ../model/struct.Message.html#method.delete
/// [Manage Messages]: ../model/permissions/constant.MANAGE_MESSAGES.html
- pub fn delete_message<C, M>(&self, channel_id: C, message_id: M)
- -> Result<()> where C: Into<ChannelId>, M: Into<MessageId> {
- rest::delete_message(channel_id.into().0, message_id.into().0)
+ pub fn delete_message<M: Into<MessageId>>(&self, message_id: M) -> Result<()> {
+ match self.channel_id {
+ Some(channel_id) => channel_id.delete_message(message_id),
+ None => Err(Error::Client(ClientError::NoChannelId)),
+ }
}
/// Deletes all messages by Ids from the given vector in the given channel.
@@ -617,137 +310,67 @@ impl Context {
///
/// **Note**: Messages that are older than 2 weeks can't be deleted using this method.
///
+ /// # Errors
+ ///
+ /// Returns a [`ClientError::NoChannelId`] if the current context is not
+ /// related to a channel.
+ ///
+ /// Returns a [`ClientError::InvalidOperationAsUser`] if the current user is
+ /// not a bot user.
+ ///
+ /// [`ClientError::InvalidOperationAsUser`]: enum.ClientError.html#variant.InvalidOperationAsUser
+ /// [`ClientError::NoChannelId`]: enum.ClientError.html#variant.NoChannelId
/// [Manage Messages]: ../model/permissions/constant.MANAGE_MESSAGES.html
- pub fn delete_messages<C>(&self, channel_id: C, message_ids: &[MessageId])
- -> Result<()> where C: Into<ChannelId> {
+ pub fn delete_messages(&self, message_ids: &[MessageId]) -> Result<()> {
if self.login_type == LoginType::User {
return Err(Error::Client(ClientError::InvalidOperationAsUser))
}
- let ids = message_ids.into_iter()
- .map(|message_id| message_id.0)
- .collect::<Vec<u64>>();
-
- let map = ObjectBuilder::new()
- .insert("messages", ids)
- .build();
-
- rest::delete_messages(channel_id.into().0, map)
- }
-
- /// Deletes a profile note from a user.
- pub fn delete_note<U: Into<UserId>>(&self, user_id: U) -> Result<()> {
- let map = ObjectBuilder::new()
- .insert("note", "")
- .build();
-
- rest::edit_note(user_id.into().0, map)
+ match self.channel_id {
+ Some(channel_id) => channel_id.delete_messages(message_ids),
+ None => Err(Error::Client(ClientError::NoChannelId)),
+ }
}
- /// Deletes all permission overrides in a channel from a member or
- /// a role.
+ /// Deletes all permission overrides in the contextual channel from a member
+ /// or role.
///
- /// Requires the [Manage Channel] permission.
+ /// **Note**: Requires the [Manage Channel] permission.
+ ///
+ /// # Errors
+ ///
+ /// Returns a [`ClientError::NoChannelId`] if the current context is not
+ /// related to a channel.
///
+ /// [`ClientError::NoChannelId`]: enum.ClientError.html#variant.NoChannelId
/// [Manage Channel]: ../model/permissions/constant.MANAGE_CHANNELS.html
- pub fn delete_permission<C>(&self,
- channel_id: C,
- permission_type: PermissionOverwriteType)
- -> Result<()> where C: Into<ChannelId> {
- let id = match permission_type {
- PermissionOverwriteType::Member(id) => id.0,
- PermissionOverwriteType::Role(id) => id.0,
- };
-
- rest::delete_permission(channel_id.into().0, id)
+ #[inline]
+ pub fn delete_permission(&self, permission_type: PermissionOverwriteType) -> Result<()> {
+ match self.channel_id {
+ Some(channel_id) => channel_id.delete_permission(permission_type),
+ None => Err(Error::Client(ClientError::NoChannelId)),
+ }
}
-
- /// Deletes the given [`Reaction`].
+ /// Deletes the given [`Reaction`] from the contextual channel.
///
/// **Note**: Requires the [Manage Messages] permission, _if_ the current
/// user did not perform the reaction.
///
- /// [`Reaction`]: ../model/struct.Reaction.html
- /// [Manage Messages]: ../model/permissions/constant.MANAGE_MESSAGES.html
- pub fn delete_reaction<C, M, R>(&self,
- channel_id: C,
- message_id: M,
- user_id: Option<UserId>,
- reaction_type: R)
- -> Result<()>
- where C: Into<ChannelId>,
- M: Into<MessageId>,
- R: Into<ReactionType> {
- rest::delete_reaction(channel_id.into().0,
- message_id.into().0,
- user_id.map(|uid| uid.0),
- reaction_type.into())
- }
-
- /// Deletes a [`Role`] by Id from the given [`Guild`].
- ///
- /// Also see [`Role::delete`] if you have the `cache` and `methods` features
- /// enabled.
- ///
- /// Requires the [Manage Roles] permission.
- ///
- /// [`Guild`]: ../model/struct.Guild.html
- /// [`Role`]: ../model/struct.Role.html
- /// [`Role::delete`]: ../model/struct.Role.html#method.delete
- /// [Manage Roles]: ../model/permissions/constant.MANAGE_ROLES.html
- pub fn delete_role<G, R>(&self, guild_id: G, role_id: R) -> Result<()>
- where G: Into<GuildId>, R: Into<RoleId> {
- rest::delete_role(guild_id.into().0, role_id.into().0)
- }
-
- /// 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
- ///
- /// There are three ways to send a direct message to someone, the first
- /// being an unrelated, although equally helpful method.
- ///
- /// Sending a message via [`User::dm`]:
- ///
- /// ```rust,ignore
- /// // assuming you are in a context
- /// let _ = context.message.author.dm("Hello!");
- /// ```
- ///
- /// Sending a message to a `PrivateChannel`:
- ///
- /// ```rust,ignore
- /// assuming you are in a context
- /// let private_channel = context.create_private_channel(context.message.author.id);
- ///
- /// let _ = context.direct_message(private_channel, "Test!");
- /// ```
- ///
- /// Sending a message to a `PrivateChannel` given its ID:
- ///
- /// ```rust,ignore
- /// use serenity::Client;
- /// use std::env;
- ///
- /// let mut client = Client::login_bot(&env::var("DISCORD_BOT_TOKEN").unwrap());
- ///
- /// client.on_message(|context, message| {
- /// if message.content == "!pm-me" {
- /// let channel = context.create_private_channel(message.author.id)
- /// .unwrap();
+ /// # Errors
///
- /// let _ = channel.send_message("test!");
- /// }
- /// });
- /// ```
+ /// Returns a [`ClientError::NoChannelId`] if the current context is not
+ /// related to a channel.
///
- /// [`PrivateChannel`]: ../model/struct.PrivateChannel.html
- /// [`User::dm`]: ../model/struct.User.html#method.dm
- pub fn dm<C: Into<ChannelId>>(&self, target_id: C, content: &str)
- -> Result<Message> {
- self.send_message(target_id.into(), |m| m.content(content))
+ /// [`ClientError::NoChannelId`]: enum.ClientError.html#variant.NoChannelId
+ /// [`Reaction`]: ../model/struct.Reaction.html
+ /// [Manage Messages]: ../model/permissions/constant.MANAGE_MESSAGES.html
+ pub fn delete_reaction<M, R>(&self, message_id: M, user_id: Option<UserId>, reaction_type: R)
+ -> Result<()> where M: Into<MessageId>, R: Into<ReactionType> {
+ match self.channel_id {
+ Some(channel_id) => channel_id.delete_reaction(message_id, user_id, reaction_type),
+ None => Err(Error::Client(ClientError::NoChannelId)),
+ }
}
/// Edits the settings of a [`Channel`], optionally setting new values.
@@ -766,128 +389,33 @@ impl Context {
/// .bitrate(64000));
/// ```
///
- /// [`Channel`]: ../model/enum.Channel.html
- pub fn edit_channel<C, F>(&self, channel_id: C, f: F)
- -> Result<GuildChannel> where C: Into<ChannelId>,
- F: FnOnce(EditChannel) -> EditChannel {
- let channel_id = channel_id.into();
-
- let map = match self.get_channel(channel_id)? {
- Channel::Guild(channel) => {
- let map = ObjectBuilder::new()
- .insert("name", channel.name)
- .insert("position", channel.position);
-
- match channel.kind {
- ChannelType::Text => map.insert("topic", channel.topic),
- ChannelType::Voice => {
- map.insert("bitrate", channel.bitrate)
- .insert("user_limit", channel.user_limit)
- },
- kind => return Err(Error::Client(ClientError::UnexpectedChannelType(kind))),
- }
- },
- Channel::Private(channel) => {
- return Err(Error::Client(ClientError::UnexpectedChannelType(channel.kind)));
- },
- Channel::Group(_group) => {
- return Err(Error::Client(ClientError::UnexpectedChannelType(ChannelType::Group)));
- },
- };
-
- let edited = f(EditChannel(map)).0.build();
-
- rest::edit_channel(channel_id.0, edited)
- }
-
- /// Edits an [`Emoji`]'s name.
- ///
- /// Also see [`Emoji::edit`] if you have the `cache` and `methods` features
- /// enabled.
- ///
- /// Requires the [Manage Emojis] permission.
- ///
- /// [`Emoji`]: ../model/struct.Emoji.html
- /// [`Emoji::edit`]: ../model/struct.Emoji.html#method.edit
- /// [Manage Emojis]: ../model/permissions/constant.MANAGE_EMOJIS.html
- pub fn edit_emoji<E, G>(&self, guild_id: G, emoji_id: E, name: &str)
- -> Result<Emoji> where E: Into<EmojiId>, G: Into<GuildId> {
- let map = ObjectBuilder::new()
- .insert("name", name)
- .build();
-
- rest::edit_emoji(guild_id.into().0, emoji_id.into().0, map)
- }
-
- /// Edits the settings of a [`Guild`], optionally setting new values.
- ///
- /// Refer to `EditGuild`'s documentation for a full list of methods.
- ///
- /// Also see [`Guild::edit`] if you have the `methods` feature enabled.
- ///
- /// Requires 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");
+ /// # Errors
///
- /// context.edit_guild(guild_id, |g|
- /// g.icon(base64_icon));
- /// ```
+ /// Returns a [`ClientError::NoChannelId`] if the current context is not
+ /// related to a guild channel.
///
- /// [`Guild`]: ../model/struct.Guild.html
- /// [`Guild::edit`]: ../model/struct.Guild.html
- /// [Manage Guild]: ../model/permissions/constant.MANAGE_GUILD.html
- pub fn edit_guild<F, G>(&self, guild_id: G, f: F) -> Result<PartialGuild>
- where F: FnOnce(EditGuild) -> EditGuild, G: Into<GuildId> {
- let map = f(EditGuild::default()).0.build();
+ /// [`Channel`]: ../model/enum.Channel.html
+ /// [`ClientError::NoChannelId`]: enum.ClientError.html#variant.NoChannelId
+ pub fn edit_channel<F>(&self, f: F) -> Result<GuildChannel>
+ where F: FnOnce(EditChannel) -> EditChannel {
+ let channel_id = match self.channel_id {
+ Some(channel_id) => channel_id,
+ None => return Err(Error::Client(ClientError::NoChannelId)),
+ };
- rest::edit_guild(guild_id.into().0, map)
- }
+ #[cfg(feature="cache")]
+ {
- /// Edits the properties of member of a 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
- /// context.edit_member(guild_id, user_id, |m| m
- /// .mute(true)
- /// .roles(&vec![role_id]));
- /// ```
- pub fn edit_member<F, G, U>(&self, guild_id: G, user_id: U, f: F)
- -> Result<()> where F: FnOnce(EditMember) -> EditMember,
- G: Into<GuildId>,
- U: Into<UserId> {
- let map = f(EditMember::default()).0.build();
+ match channel_id.get()? {
+ Channel::Guild(ref c) if c.kind != ChannelType::Text &&
+ c.kind != ChannelType::Voice => {
+ return Err(Error::Client(ClientError::UnexpectedChannelType(c.kind)));
+ },
+ _ => {},
+ }
+ }
- rest::edit_member(guild_id.into().0, user_id.into().0, map)
- }
-
- /// Edits the current user's nickname for the provided [`Guild`] via its Id.
- ///
- /// Pass `None` to reset the nickname.
- ///
- /// Requires the [Change Nickname] permission.
- ///
- /// [`Guild`]: ../../model/struct.Guild.html
- /// [Change Nickname]: permissions/constant.CHANGE_NICKNAME.html
- #[inline]
- pub fn edit_nickname<G>(&self, guild_id: G, new_nickname: Option<&str>)
- -> Result<()> where G: Into<GuildId> {
- rest::edit_nickname(guild_id.into().0, new_nickname)
+ channel_id.edit(f)
}
/// Edits the current user's profile settings.
@@ -901,243 +429,89 @@ impl Context {
/// ```rust,ignore
/// context.edit_profile(|p| p.username("Hakase"));
/// ```
- pub fn edit_profile<F: FnOnce(EditProfile) -> EditProfile>(&self, f: F)
- -> Result<CurrentUser> {
- let user = rest::get_current_user()?;
+ pub fn edit_profile<F: FnOnce(EditProfile) -> EditProfile>(&self, f: F) -> Result<CurrentUser> {
+ let mut map = ObjectBuilder::new();
- let mut map = ObjectBuilder::new()
- .insert("avatar", user.avatar)
- .insert("username", user.name);
-
- if let Some(email) = user.email.as_ref() {
- map = map.insert("email", email);
- }
-
- let edited = f(EditProfile(map)).0.build();
+ feature_cache! {{
+ let cache = CACHE.read().unwrap();
- rest::edit_profile(edited)
- }
+ map = map.insert("avatar", &cache.user.avatar)
+ .insert("username", &cache.user.name);
- /// Edits a [`Role`], optionally setting its new fields.
- ///
- /// Requires the [Manage Roles] permission.
- ///
- /// # Examples
- ///
- /// Make a role hoisted:
- ///
- /// ```rust,ignore
- /// context.edit_role(guild_id, role_id, |r| r
- /// .hoist(true));
- /// ```
- ///
- /// [`Role`]: ../model/struct.Role.html
- /// [Manage Roles]: ../model/permissions/constant.MANAGE_ROLES.html
- pub fn edit_role<F, G, R>(&self, guild_id: G, role_id: R, f: F)
- -> Result<Role> where F: FnOnce(EditRole) -> EditRole,
- G: Into<GuildId>,
- R: Into<GuildId> {
- let guild_id = guild_id.into();
- let role_id = role_id.into();
+ if let Some(email) = cache.user.email.as_ref() {
+ map = map.insert("email", email);
+ }
+ } else {
+ let user = rest::get_current_user()?;
- let map = feature_cache! {{
- let cache = CACHE.read().unwrap();
+ map = map.insert("avatar", user.avatar)
+ .insert("username", user.name);
- let role = if let Some(role) = {
- cache.get_role(guild_id.0, role_id.0)
- } {
- role
- } else {
- return Err(Error::Client(ClientError::RecordNotFound));
- };
+ if let Some(email) = user.email.as_ref() {
+ map = map.insert("email", email);
+ }
+ }}
- f(EditRole::new(role)).0.build()
- } else {
- f(EditRole::default()).0.build()
- }};
+ let edited = f(EditProfile(map)).0.build();
- rest::edit_role(guild_id.0, role_id.0, map)
+ rest::edit_profile(edited)
}
/// Edits a [`Message`] given its Id and the Id of the channel it belongs
/// to.
///
- /// Pass an empty string (`""`) to `text` if you are editing a message with
- /// an embed or file but no content. Otherwise, `text` must be given.
+ /// Refer to [`Channel::edit_message`] for more information.
///
/// **Note**: Requires that the current user be the author of the message.
///
+ /// # Errors
+ ///
+ /// Returns a [`ClientError::NoChannelId`] if the current context is not
+ /// related to a channel.
+ ///
+ /// [`Channel::edit_message`]: ../model/enum.Channel.html#method.edit_message
+ /// [`ClientError::NoChannelId`]: enum.ClientError.html#variant.NoChannelId
/// [`Message`]: ../model/struct.Message.html
- pub fn edit_message<C, F, M>(&self, channel_id: C, message_id: M, text: &str, f: F)
- -> Result<Message> where C: Into<ChannelId>,
- F: FnOnce(CreateEmbed) -> CreateEmbed,
- M: Into<MessageId> {
- let mut map = ObjectBuilder::new()
- .insert("content", text);
-
- let embed = f(CreateEmbed::default()).0;
-
- if embed.len() > 1 {
- map = map.insert("embed", Value::Object(embed));
+ pub fn edit_message<F, M>(&self, message_id: M, text: &str, f: F) -> Result<Message>
+ where F: FnOnce(CreateEmbed) -> CreateEmbed, M: Into<MessageId> {
+ match self.channel_id {
+ Some(channel_id) => channel_id.edit_message(message_id, text, f),
+ None => Err(Error::Client(ClientError::NoChannelId)),
}
-
- rest::edit_message(channel_id.into().0, message_id.into().0, map.build())
}
- /// Edits the note that the current user has set for another user.
- ///
- /// Use [`delete_note`] to remove a note.
- ///
- /// **Note**: Requires that the current user be a user account.
- ///
- /// # Examples
- ///
- /// Set a note for a message's author:
- ///
- /// ```rust,ignore
- /// // assuming a `message` has been bound
- /// let _ = context.edit_note(message.author, "test note");
- /// ```
+ /// Gets a fresh version of the channel over the REST API.
///
/// # Errors
///
- /// Returns a [`ClientError::InvalidOperationAsBot`] if the current user is
- /// a bot user.
- ///
- /// [`ClientError::InvalidOperationAsBot`]: enum.ClientError.html#variant.InvalidOperationAsBot
- /// [`delete_note`]: #method.delete_note
- pub fn edit_note<U: Into<UserId>>(&self, user_id: U, note: &str)
- -> Result<()> {
- let map = ObjectBuilder::new()
- .insert("note", note)
- .build();
-
- rest::edit_note(user_id.into().0, map)
- }
-
- /// Gets a list of the given [`Guild`]'s bans.
- ///
- /// Requires the [Ban Members] permission.
+ /// Returns a [`ClientError::NoChannelId`] if the current context is not
+ /// related to a channel.
///
- /// [`Guild`]: ../model/struct.Guild.html
- /// [Ban Members]: ../model/permissions/constant.BAN_MEMBERS.html
- pub fn get_bans<G: Into<GuildId>>(&self, guild_id: G) -> Result<Vec<Ban>> {
- rest::get_bans(guild_id.into().0)
+ /// [`ClientError::NoChannelId`]: enum.ClientError.html#variant.NoChannelId
+ pub fn get_channel(&self) -> Result<Channel> {
+ match self.channel_id {
+ Some(channel_id) => channel_id.get(),
+ None => Err(Error::Client(ClientError::NoChannelId)),
+ }
}
/// Gets all of a [`GuildChannel`]'s invites.
///
/// Requires the [Manage Guild] permission.
///
+ /// # Errors
+ ///
+ /// Returns a [`ClientError::NoChannelId`] if the current context is not
+ /// related to a channel.
+ ///
+ /// [`ClientError::NoChannelId`]: enum.ClientError.html#variant.NoChannelId
/// [`GuildChannel`]: ../model/struct.GuildChannel.html
/// [Manage Guild]: ../model/permissions/constant.MANAGE_GUILD.html
- pub fn get_channel_invites<C: Into<ChannelId>>(&self, channel_id: C)
- -> Result<Vec<RichInvite>> {
- rest::get_channel_invites(channel_id.into().0)
- }
-
- /// Gets a `Channel` by the given Id.
- pub fn get_channel<C>(&self, channel_id: C) -> Result<Channel>
- where C: Into<ChannelId> {
- let channel_id = channel_id.into();
-
- #[cfg(feature="cache")]
- {
- if let Some(channel) = CACHE.read().unwrap().get_channel(channel_id) {
- return Ok(channel.clone_inner());
- }
+ pub fn get_channel_invites(&self) -> Result<Vec<RichInvite>> {
+ match self.channel_id {
+ Some(channel_id) => channel_id.get_invites(),
+ None => Err(Error::Client(ClientError::NoChannelId)),
}
-
- rest::get_channel(channel_id.0)
- }
-
- /// Gets all of a [`Guild`]'s channels with given Id.
- ///
- /// [`Guild`]: ../model/struct.Guild.html
- pub fn get_channels<G>(&self, guild_id: G)
- -> Result<HashMap<ChannelId, GuildChannel>> where G: Into<GuildId> {
- let guild_id = guild_id.into();
-
- #[cfg(feature="cache")]
- {
- if let Some(guild) = CACHE.read().unwrap().get_guild(guild_id) {
- return Ok(guild.channels.clone());
- }
- }
-
- let mut channels = HashMap::new();
-
- for channel in rest::get_channels(guild_id.0)? {
- channels.insert(channel.id, channel);
- }
-
- Ok(channels)
- }
-
- /// Gets information about the current user.
- ///
- /// Note this is shorthand for retrieving the current user through the
- /// cache, and will perform a clone.
- #[cfg(all(feature = "cache", feature = "methods"))]
- pub fn get_current_user(&self) -> CurrentUser {
- CACHE.read().unwrap().user.clone()
- }
-
- /// Gets an [`Guild`]'s emoji by Id.
- ///
- /// Requires the [Manage Emojis] permission.
- ///
- /// [`Guild`]: ../model/struct.Guild.html
- /// [Manage Emojis]: ../model/permissions/constant.MANAGE_EMOJIS.html
- pub fn get_emoji<E, G>(&self, guild_id: G, emoji_id: E) -> Result<Emoji>
- where E: Into<EmojiId>, G: Into<GuildId> {
- rest::get_emoji(guild_id.into().0, emoji_id.into().0)
- }
-
- /// Gets a list of all of a [`Guild`]'s emojis.
- ///
- /// Requires the [Manage Emojis] permission.
- ///
- /// [`Guild`]: ../model/struct.Guild.html
- /// [Manage Emojis]: ../model/permissions/constant.MANAGE_EMOJIS.html
- pub fn get_emojis<G: Into<GuildId>>(&self, guild_id: G)
- -> Result<Vec<Emoji>> {
- rest::get_emojis(guild_id.into().0)
- }
-
- /// Gets a partial amount of guild data by its Id.
- ///
- /// Requires that the current user be in the guild.
- pub fn get_guild<G: Into<GuildId>>(&self, guild_id: G)
- -> Result<PartialGuild> {
- rest::get_guild(guild_id.into().0)
- }
-
- /// Gets all of a guild's invites.
- ///
- /// Requires the [Manage Guild] permission.
- ///
- /// [`RichInvite`]: ../model/struct.RichInvite.html
- /// [Manage Guild]: ../model/permissions/struct.MANAGE_GUILD.html
- pub fn get_guild_invites<G>(&self, guild_id: G) -> Result<Vec<RichInvite>>
- where G: Into<GuildId> {
- rest::get_guild_invites(guild_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`]: ../model/struct.Member.html
- /// [Kick Members]: ../model/permissions/constant.KICK_MEMBERS.html
- pub fn get_guild_prune_count<G>(&self, guild_id: G, days: u16)
- -> Result<GuildPrune> where G: Into<GuildId> {
- let map = ObjectBuilder::new()
- .insert("days", days)
- .build();
-
- rest::get_guild_prune_count(guild_id.into().0, map)
}
/// Gets a paginated list of guilds that the current user is in.
@@ -1161,63 +535,12 @@ impl Context {
///
/// [`CurrentUser::guilds`]: ../model/struct.CurrentUser.html#method.guilds
/// [`Message`]: ../model/struct.Message.html
+ #[inline]
pub fn get_guilds(&self, target: GuildPagination, limit: u8) -> Result<Vec<GuildInfo>> {
rest::get_guilds(target, limit as u64)
}
- /// Gets all integrations of a guild via the given Id.
- pub fn get_integrations<G: Into<GuildId>>(&self, guild_id: G)
- -> Result<Vec<Integration>> {
- rest::get_guild_integrations(guild_id.into().0)
- }
-
- /// Gets the information about an invite.
- pub fn get_invite(&self, invite: &str) -> Result<Invite> {
- let code = utils::parse_invite(invite);
-
- rest::get_invite(code)
- }
-
- /// Gets a user's [`Member`] instance for a [`Guild`], given by Id.
- ///
- /// If the `cache` feature is enabled, then the instance will be cloned from
- /// the cache if it exists.
- ///
- /// [`Guild`]: ../model/struct.Guild.html
- /// [`Member`]: ../model/struct.Member.html
- pub fn get_member<G, U>(&self, guild_id: G, user_id: U) -> Result<Member>
- where G: Into<GuildId>, U: Into<UserId> {
- let guild_id = guild_id.into();
- let user_id = user_id.into();
-
- #[cfg(feature="cache")]
- {
- let cache = CACHE.read().unwrap();
-
- if let Some(member) = cache.get_member(guild_id, user_id) {
- return Ok(member.clone());
- }
- }
-
- rest::get_member(guild_id.0, user_id.0)
- }
-
- /// Gets a list of a [`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.
- ///
- /// [`Guild`]: ../model/struct.Guild.html
- /// [`User`]: ../model/struct.User.html
- pub fn get_members<G, U>(&self, guild_id: G, limit: Option<u64>, after: Option<U>)
- -> Result<Vec<Member>> where G: Into<GuildId>, U: Into<UserId> {
- rest::get_guild_members(guild_id.into().0,
- limit,
- after.map(|x| x.into().0))
- }
-
- /// Gets a single [`Message`] from a [`Channel`].
+ /// Gets a single [`Message`] from the contextual channel.
///
/// Requires the [Read Message History] permission.
///
@@ -1226,50 +549,22 @@ impl Context {
/// Returns a [`ClientError::InvalidOperationAsUser`] if the current user is
/// not a user account.
///
- /// [`Channel`]: ../model/struct.Channel.html
- /// [`ClientError::InvalidOperationAsUser`]: ../enum.ClientError.html#variant.InvalidOperationAsUser
+ /// Returns a [`ClientError::NoChannelId`] if the current context is not
+ /// related to a channel.
+ ///
+ /// [`ClientError::InvalidOperationAsUser`]: enum.ClientError.html#variant.InvalidOperationAsUser
+ /// [`ClientError::NoChannelId`]: enum.ClientError.html#variant.NoChannelId
/// [`Message`]: ../model/struct.Message.html
/// [Read Message History]: ../model/permissions/constant.READ_MESSAGE_HISTORY.html
- pub fn get_message<C, M>(&self, channel_id: C, message_id: M)
- -> Result<Message> where C: Into<ChannelId>, M: Into<MessageId> {
+ pub fn get_message<M: Into<MessageId>>(&self, message_id: M) -> Result<Message> {
if self.login_type == LoginType::User {
return Err(Error::Client(ClientError::InvalidOperationAsUser))
}
- rest::get_message(channel_id.into().0, message_id.into().0)
- }
-
- /// Gets messages from a specific channel.
- ///
- /// Requires the [Read Message History] permission.
- ///
- /// # Examples
- ///
- /// ```rust,ignore
- /// let role = context.get_messages(channel_id, |g| g
- /// .before(20)
- /// .after(100)); // Maximum is 100.
- /// ```
- ///
- /// [Read Message History]: ../model/permission/constant.READ_MESSAGE_HISTORY.html
- pub fn get_messages<C, F>(&self, channel_id: C, f: F) -> Result<Vec<Message>>
- where C: Into<ChannelId>, F: FnOnce(GetMessages) -> GetMessages {
- let mut map = f(GetMessages::default()).0;
- let mut query = format!("?limit={}", map.remove("limit").unwrap_or(50));
-
- if let Some(after) = map.remove("after") {
- write!(query, "&after={}", after)?;
- }
-
- if let Some(around) = map.remove("around") {
- write!(query, "&around={}", around)?;
+ match self.channel_id {
+ Some(channel_id) => channel_id.get_message(message_id),
+ None => Err(Error::Client(ClientError::NoChannelId)),
}
-
- if let Some(before) = map.remove("before") {
- write!(query, "&before={}", before)?;
- }
-
- rest::get_messages(channel_id.into().0, &query)
}
/// Gets the list of [`User`]s who have reacted to a [`Message`] with a
@@ -1284,86 +579,46 @@ impl Context {
///
/// **Note**: Requires the [Read Message History] permission.
///
+ /// # Errors
+ ///
+ /// Returns a [`ClientError::NoChannelId`] if the current context is not
+ /// related to a channel.
+ ///
+ /// [`ClientError::NoChannelId`]: enum.ClientError.html#variant.NoChannelId
/// [`Emoji`]: struct.Emoji.html
/// [`Message`]: struct.Message.html
/// [`User`]: struct.User.html
/// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
- pub fn get_reaction_users<C, M, R, U>(&self,
- channel_id: C,
- message_id: M,
- reaction_type: R,
- limit: Option<u8>,
- after: Option<U>)
- -> Result<Vec<User>>
- where C: Into<ChannelId>,
- M: Into<MessageId>,
- R: Into<ReactionType>,
- U: Into<UserId> {
- let limit = limit.map_or(50, |x| if x > 100 { 100 } else { x });
-
- rest::get_reaction_users(channel_id.into().0,
- message_id.into().0,
- reaction_type.into(),
- limit,
- after.map(|u| u.into().0))
+ pub fn get_reaction_users<M, R, U>(&self,
+ message_id: M,
+ reaction_type: R,
+ limit: Option<u8>,
+ after: Option<U>)
+ -> Result<Vec<User>> where M: Into<MessageId>, R: Into<ReactionType>, U: Into<UserId> {
+ match self.channel_id {
+ Some(c) => c.get_reaction_users(message_id, reaction_type, limit, after),
+ None => Err(Error::Client(ClientError::NoChannelId)),
+ }
}
- /// Gets a [`User`] by its Id.
+ /// Pins a [`Message`] in the specified [`Channel`] by its Id.
///
- /// [`User`]: ../model/struct.User.html
+ /// Requires the [Manage Messages] permission.
///
/// # Errors
///
- /// Returns a [`ClientError::InvalidOperationAsUser`] if the current user is
- /// not a bot user.
+ /// Returns a [`ClientError::NoChannelId`] if the current context is not
+ /// related to a channel.
///
- /// [`ClientError::InvalidOperationAsUser`]: enum.ClientError.html#variant.InvalidOperationAsUser
- #[inline]
- pub fn get_user<U: Into<UserId>>(&self, user_id: U) -> Result<User> {
- #[cfg(feature="cache")]
- {
- if !CACHE.read().unwrap().user.bot {
- return Err(Error::Client(ClientError::InvalidOperationAsUser));
- }
+ /// [`Channel`]: ../model/enum.Channel.html
+ /// [`ClientError::NoChannelId`]: enum.ClientError.html#variant.NoChannelId
+ /// [`Message`]: ../model/struct.Message.html
+ /// [Manage Messages]: ../model/permissions/constant.MANAGE_MESSAGES.html
+ pub fn pin<M: Into<MessageId>>(&self, message_id: M) -> Result<()> {
+ match self.channel_id {
+ Some(channel_id) => channel_id.pin(message_id),
+ None => Err(Error::Client(ClientError::NoChannelId)),
}
-
- rest::get_user(user_id.into().0)
- }
-
- /// Kicks a [`Member`] from the specified [`Guild`] if they are in it.
- ///
- /// Requires the [Kick Members] permission.
- ///
- /// [`Guild`]: ../model/struct.Guild.html
- /// [`Member`]: ../model/struct.Member.html
- /// [Kick Members]: ../model/permissions/constant.KICK_MEMBERS.html
- pub fn kick_member<G, U>(&self, guild_id: G, user_id: U) -> Result<()>
- where G: Into<GuildId>, U: Into<UserId> {
- rest::kick_member(guild_id.into().0, user_id.into().0)
- }
-
- /// Leaves a [`Guild`] by its Id.
- ///
- /// [`Guild`]: ../model/struct.Guild.html
- pub fn leave_guild<G: Into<GuildId>>(&self, guild_id: G)
- -> Result<PartialGuild> {
- rest::leave_guild(guild_id.into().0)
- }
-
- /// Moves a member to a specific voice channel.
- ///
- /// Requires the [Move Members] permission.
- ///
- /// [Move Members]: ../model/permissions/constant.MOVE_MEMBERS.html
- pub fn move_member<C, G, U>(&self, guild_id: G, user_id: U, channel_id: C)
- -> Result<()> where C: Into<ChannelId>,
- G: Into<GuildId>,
- U: Into<UserId> {
- let map = ObjectBuilder::new()
- .insert("channel_id", channel_id.into().0)
- .build();
-
- rest::edit_member(guild_id.into().0, user_id.into().0, map)
}
/// Gets the list of [`Message`]s which are pinned to the specified
@@ -1371,22 +626,11 @@ impl Context {
///
/// [`Channel`]: ../model/enum.Channel.html
/// [`Message`]: ../model/struct.Message.html
- pub fn get_pins<C>(&self, channel_id: C) -> Result<Vec<Message>>
- where C: Into<ChannelId> {
- rest::get_pins(channel_id.into().0)
- }
-
- /// Pins a [`Message`] in the specified [`Channel`] by its Id.
- ///
- /// Requires the [Manage Messages] permission.
- ///
- /// [`Channel`]: ../model/enum.Channel.html
- /// [`Message`]: ../model/struct.Message.html
- ///
- /// [Manage Messages]: ../model/permissions/constant.MANAGE_MESSAGES.html
- pub fn pin<C, M>(&self, channel_id: C, message_id: M) -> Result<()>
- where C: Into<ChannelId>, M: Into<MessageId> {
- rest::pin_message(channel_id.into().0, message_id.into().0)
+ pub fn pins(&self) -> Result<Vec<Message>> {
+ match self.channel_id {
+ Some(channel_id) => channel_id.pins(),
+ None => Err(Error::Client(ClientError::NoChannelId)),
+ }
}
/// Sends a message with just the given message content in the channel that
@@ -1423,7 +667,7 @@ impl Context {
///
/// [`ChannelId`]: ../../model/struct.ChannelId.html
/// [`ClientError::MessageTooLong`]: enum.ClientError.html#variant.MessageTooLong
- /// [`ClientError::NoChannelId`]: ../enum.ClientError.html#NoChannelId
+ /// [`ClientError::NoChannelId`]: enum.ClientError.html#NoChannelId
/// [`Event::ChannelCreate`]: ../model/event/enum.Event.html#variant.ChannelCreate
/// [`Event::ChannelPinsAck`]: ../model/event/enum.Event.html#variant.ChannelPinsAck
/// [`Event::ChannelPinsUpdate`]: ../model/event/enum.Event.html#variant.ChannelPinsUpdate
@@ -1439,10 +683,9 @@ impl Context {
/// [`Event::ReactionRemoveAll`]: ../model/event/enum.Event.html#variant.ReactionRemoveAll
/// [`Message`]: ../model/struct.Message.html
pub fn say(&self, content: &str) -> Result<Message> {
- if let Some(channel_id) = self.channel_id {
- self.send_message(channel_id, |m| m.content(content))
- } else {
- Err(Error::Client(ClientError::NoChannelId))
+ match self.channel_id {
+ Some(channel_id) => channel_id.send_message(|m| m.content(content)),
+ None => Err(Error::Client(ClientError::NoChannelId)),
}
}
@@ -1478,55 +721,17 @@ impl Context {
/// If the `cache` is enabled, returns a
/// [`ClientError::InvalidOperationAsBot`] if the current user is a bot.
///
- /// [`ClientError::InvalidOperationAsBot`]: ../client/enum.ClientError.html#variant.InvalidOperationAsBot
+ /// [`ClientError::InvalidOperationAsBot`]: enum.ClientError.html#variant.InvalidOperationAsBot
/// [`Channel`]: ../model/enum.Channel.html
/// [`Search`]: ../utils/builder/struct.Search.html
- /// [search channel]: ../../utils/builder/struct.Search.html#searching-a-channel
- pub fn search_channel<C, F>(&self, channel_id: C, f: F)
- -> Result<SearchResult> where C: Into<ChannelId>,
- F: FnOnce(Search) -> Search {
- #[cfg(feature="cache")]
- {
- if CACHE.read().unwrap().user.bot {
- return Err(Error::Client(ClientError::InvalidOperationAsBot));
- }
- }
-
- let map = f(Search::default()).0;
-
- rest::search_channel_messages(channel_id.into().0, map)
- }
+ /// [search channel]: ../utils/builder/struct.Search.html#searching-a-channel
+ pub fn search_channel<F>(&self, f: F) -> Result<SearchResult>
+ where F: FnOnce(Search) -> Search {
+ let channel_id = match self.channel_id {
+ Some(channel_id) => channel_id,
+ None => return Err(Error::Client(ClientError::NoChannelId)),
+ };
- /// Searches a [`Guild`]'s messages by providing query parameters via the
- /// search builder, with the ability to narrow down channels to search.
- ///
- /// Refer to the documentation for the [`Search`] builder for restrictions
- /// and default parameters, as well as potentially advanced usage.
- ///
- /// **Note**: Bot users can not search.
- ///
- /// # Examples
- ///
- /// Refer to the [`Search`] builder's documentation for more examples,
- /// specifically the section on
- /// [searching a guild's channels][search guild].
- ///
- /// # Errors
- ///
- /// If the `cache` is enabled, returns a
- /// [`ClientError::InvalidOperationAsBot`] if the current user is a bot.
- ///
- /// [`ClientError::InvalidOperationAsBot`]: ../client/enum.ClientError.html#variant.InvalidOperationAsBot
- /// [`Guild`]: ../model/struct.Guild.html
- /// [`Search`]: ../utils/builder/struct.Search.html
- /// [search guild]: ../../utils/builder/struct.Search.html#searching-a-guilds-channels
- pub fn search_guild<F, G>(&self,
- guild_id: G,
- channel_ids: Vec<ChannelId>,
- f: F)
- -> Result<SearchResult>
- where F: FnOnce(Search) -> Search,
- G: Into<GuildId> {
#[cfg(feature="cache")]
{
if CACHE.read().unwrap().user.bot {
@@ -1534,10 +739,7 @@ impl Context {
}
}
- let map = f(Search::default()).0;
- let ids = channel_ids.iter().map(|ch| ch.0).collect::<Vec<u64>>();
-
- rest::search_guild_messages(guild_id.into().0, &ids, map)
+ channel_id.search(f)
}
/// Sends a file along with optional message contents. The filename _must_
@@ -1564,23 +766,12 @@ impl Context {
/// [`GuildChannel`]: ../model/struct.GuildChannel.html
/// [Attach Files]: ../model/permissions/constant.ATTACH_FILES.html
/// [Send Messages]: ../model/permissions/constant.SEND_MESSAGES.html
- pub fn send_file<C, F, R>(&self, channel_id: C, file: R, filename: &str, f: F)
- -> Result<Message> where C: Into<ChannelId>,
- F: FnOnce(CreateMessage) -> CreateMessage,
- R: Read {
- let mut map = f(CreateMessage::default()).0;
-
- if let Some(content) = map.get("content") {
- if let Value::String(ref content) = *content {
- if let Some(length_over) = Message::overflow_length(content) {
- return Err(Error::Client(ClientError::MessageTooLong(length_over)));
- }
- }
+ pub fn send_file<F, R>(&self, file: R, filename: &str, f: F) -> Result<Message>
+ where F: FnOnce(CreateMessage) -> CreateMessage, R: Read {
+ match self.channel_id {
+ Some(channel_id) => channel_id.send_file(file, filename, f),
+ None => Err(Error::Client(ClientError::NoChannelId)),
}
-
- let _ = map.remove("embed");
-
- rest::send_file(channel_id.into().0, file, filename, map)
}
/// Sends a message to a [`Channel`].
@@ -1692,19 +883,12 @@ impl Context {
/// [Send Messages]: ../model/permissions/constant.SEND_MESSAGES.html
/// [author structure]: ../utils/builder/struct.CreateEmbedAuthor.html
/// [field structure]: ../utils/builder/struct.CreateEmbedField.html
- pub fn send_message<C, F>(&self, channel_id: C, f: F) -> Result<Message>
- where C: Into<ChannelId>, F: FnOnce(CreateMessage) -> CreateMessage {
- let map = f(CreateMessage::default()).0;
-
- if let Some(content) = map.get(&"content".to_owned()) {
- if let Value::String(ref content) = *content {
- if let Some(length_over) = Message::overflow_length(content) {
- return Err(Error::Client(ClientError::MessageTooLong(length_over)));
- }
- }
+ pub fn send_message<F>(&self, f: F) -> Result<Message>
+ where F: FnOnce(CreateMessage) -> CreateMessage {
+ match self.channel_id {
+ Some(channel_id) => channel_id.send_message(f),
+ None => Err(Error::Client(ClientError::NoChannelId)),
}
-
- rest::send_message(channel_id.into().0, Value::Object(map))
}
/// Sets the current user as being [`Online`]. This maintains the current
@@ -1841,58 +1025,18 @@ impl Context {
.set_presence(game, status, afk)
}
- /// Deletes an undefined amount of members from the given guild
- /// based on the amount of days they've been offline for.
- ///
- /// **Note**: This will trigger [`GuildMemberRemove`] events.
- ///
- /// **Note**: Requires the [Kick Members] permission.
- ///
- /// [`GuildMemberRemove`]: ../model/event/enum.Event.html#variant.GuildMemberRemove
- /// [Kick Members]: ../model/permissions/constant.KICK_MEMBERS.html
- pub fn start_guild_prune<G>(&self, guild_id: G, days: u16)
- -> Result<GuildPrune> where G: Into<GuildId> {
- let map = ObjectBuilder::new()
- .insert("days", days)
- .build();
-
- rest::start_guild_prune(guild_id.into().0, map)
- }
-
- /// Starts integration synchronization by the given integration Id.
- ///
- /// Requires the [Manage Guild] permission.
- ///
- /// [Manage Guild]: ../model/permissions/constant.MANAGE_GUILD.html
- pub fn start_integration_sync<G, I>(&self, guild_id: G, integration_id: I)
- -> Result<()> where G: Into<GuildId>, I: Into<IntegrationId> {
- rest::start_integration_sync(guild_id.into().0, integration_id.into().0)
- }
-
- /// Unbans a [`User`] from a [`Guild`].
- ///
- /// Requires the [Ban Members] permission.
- ///
- /// [`Guild`]: ../model/struct.Guild.html
- /// [`User`]: ../model/struct.User.html
- /// [Ban Members]: ../model/permissions/constant.BAN_MEMBERS.html
- pub fn unban<G, U>(&self, guild_id: G, user_id: U) -> Result<()>
- where G: Into<GuildId>, U: Into<UserId> {
- rest::remove_ban(guild_id.into().0, user_id.into().0)
- }
-
-
- /// Unpins a [`Message`] in the specified [`Channel`] given each Id.
+ /// Unpins a [`Message`] in the contextual channel given by its Id.
///
/// Requires the [Manage Messages] permission.
///
/// [`Channel`]: ../model/enum.Channel.html
/// [`Message`]: ../model/struct.Message.html
- ///
/// [Manage Messages]: ../model/permissions/constant.MANAGE_MESSAGES.html
- pub fn unpin<C, M>(&self, channel_id: C, message_id: M) -> Result<()>
- where C: Into<ChannelId>, M: Into<MessageId> {
- rest::unpin_message(channel_id.into().0, message_id.into().0)
+ pub fn unpin<M: Into<MessageId>>(&self, message_id: M) -> Result<()> {
+ match self.channel_id {
+ Some(channel_id) => channel_id.unpin(message_id),
+ None => Err(Error::Client(ClientError::NoChannelId)),
+ }
}
}
diff --git a/src/client/rest/mod.rs b/src/client/rest/mod.rs
index 43f8f8c..fd4cc2f 100644
--- a/src/client/rest/mod.rs
+++ b/src/client/rest/mod.rs
@@ -517,7 +517,7 @@ pub fn delete_reaction(channel_id: u64,
user_id: Option<u64>,
reaction_type: ReactionType)
-> Result<()> {
- let user = user_id.map(|uid| uid.to_string()).unwrap_or("@me".to_string());
+ let user = user_id.map(|uid| uid.to_string()).unwrap_or_else(|| "@me".to_string());
verify(204, request!(Route::ChannelsIdMessagesIdReactionsUserIdType(channel_id),
delete,
@@ -702,7 +702,6 @@ pub fn edit_note(user_id: u64, map: Value) -> Result<()> {
/// **Note**: this token change may cause requests made between the actual token
/// change and when the token is internally changed to be invalid requests, as
/// the token may be outdated.
-///
pub fn edit_profile(map: Value) -> Result<CurrentUser> {
let body = serde_json::to_string(&map)?;
let response = request!(Route::UsersMe, patch(body), "/users/@me");
diff --git a/src/ext/framework/help_commands.rs b/src/ext/framework/help_commands.rs
index 87b69a0..863f3fd 100644
--- a/src/ext/framework/help_commands.rs
+++ b/src/ext/framework/help_commands.rs
@@ -7,8 +7,8 @@ use ::client::Context;
use ::model::Message;
use ::utils::Colour;
-fn error_embed(ctx: &mut Context, message: &Message, input: &str) {
- let _ = ctx.send_message(message.channel_id, |m| m
+fn error_embed(ctx: &mut Context, input: &str) {
+ let _ = ctx.send_message(|m| m
.embed(|e| e
.colour(Colour::dark_red())
.description(input)));
@@ -27,7 +27,7 @@ fn remove_aliases(cmds: &HashMap<String, CommandOrAlias>) -> HashMap<&String, &I
}
pub fn with_embeds(ctx: &mut Context,
- message: &Message,
+ _: &Message,
groups: HashMap<String, Arc<CommandGroup>>,
args: Vec<String>) -> Result<(), String> {
if !args.is_empty() {
@@ -49,7 +49,7 @@ pub fn with_embeds(ctx: &mut Context,
found = Some((command_name, cmd));
},
CommandOrAlias::Alias(ref name) => {
- error_embed(ctx, message, &format!("Did you mean \"{}\"?", name));
+ error_embed(ctx, &format!("Did you mean \"{}\"?", name));
return Ok(());
}
}
@@ -58,12 +58,12 @@ pub fn with_embeds(ctx: &mut Context,
if let Some((command_name, command)) = found {
if !command.help_available {
- error_embed(ctx, message, "**Error**: No help available.");
+ error_embed(ctx, "**Error**: No help available.");
return Ok(());
}
- let _ = ctx.send_message(message.channel_id, |m| {
+ let _ = ctx.send_message(|m| {
m.embed(|e| {
let mut embed = e.colour(Colour::rosewater())
.title(command_name);
@@ -110,13 +110,13 @@ pub fn with_embeds(ctx: &mut Context,
}
let error_msg = format!("**Error**: Command `{}` not found.", name);
- error_embed(ctx, message, &error_msg);
+ error_embed(ctx, &error_msg);
return Ok(());
}
- let _ = ctx.send_message(message.channel_id, |m| {
- m.embed(|mut e| {
+ let _ = ctx.send_message(|m| m
+ .embed(|mut e| {
e = e.colour(Colour::rosewater())
.description("To get help with an individual command, pass its \
name as an argument to this command.");
@@ -146,8 +146,7 @@ pub fn with_embeds(ctx: &mut Context,
}
e
- })
- });
+ }));
Ok(())
}
diff --git a/src/ext/framework/mod.rs b/src/ext/framework/mod.rs
index ccb81f1..988d3a3 100644
--- a/src/ext/framework/mod.rs
+++ b/src/ext/framework/mod.rs
@@ -360,7 +360,7 @@ impl Framework {
return;
}
- #[cfg(all(feature="cache", feature="methods"))]
+ #[cfg(feature="cache")]
{
if !self.configuration.allow_dm && message.is_private() {
if let Some(ref message) = self.configuration.no_dm_message {
diff --git a/src/model/channel.rs b/src/model/channel.rs
index a773cc7..bda26e5 100644
--- a/src/model/channel.rs
+++ b/src/model/channel.rs
@@ -1,5 +1,9 @@
+use hyper::Client as HyperClient;
+use serde_json::builder::ObjectBuilder;
use std::borrow::Cow;
use std::fmt::{self, Write};
+use std::io::Read;
+use std::mem;
use super::utils::{
decode_id,
into_map,
@@ -8,34 +12,29 @@ use super::utils::{
remove,
};
use super::*;
+use ::client::rest;
use ::constants;
use ::internal::prelude::*;
+use ::utils::builder::{
+ CreateEmbed,
+ CreateInvite,
+ CreateMessage,
+ EditChannel,
+ GetMessages,
+ Search
+};
use ::utils::decode_array;
-#[cfg(feature="methods")]
-use hyper::Client as HyperClient;
-#[cfg(feature="methods")]
-use serde_json::builder::ObjectBuilder;
-#[cfg(feature="methods")]
-use std::io::Read;
-#[cfg(feature="methods")]
-use std::mem;
-#[cfg(all(feature="cache", feature="methods"))]
+#[cfg(feature="cache")]
use super::utils;
-
-#[cfg(all(feature="cache", feature="methods"))]
+#[cfg(feature="cache")]
use ::client::CACHE;
-#[cfg(feature="methods")]
-use ::client::rest;
-#[cfg(all(feature="cache", feature="methods"))]
+#[cfg(feature="cache")]
use ::ext::cache::ChannelRef;
-#[cfg(feature="methods")]
-use ::utils::builder::{CreateEmbed, CreateInvite, EditChannel, Search};
impl Attachment {
/// If this attachment is an image, then a tuple of the width and height
/// in pixels is returned.
- #[cfg(feature="methods")]
pub fn dimensions(&self) -> Option<(u64, u64)> {
if let (Some(width), Some(height)) = (self.width, self.height) {
Some((width, height))
@@ -110,7 +109,6 @@ impl Attachment {
/// [`Error::Hyper`]: ../enum.Error.html#variant.Hyper
/// [`Error::Io`]: ../enum.Error.html#variant.Io
/// [`Message`]: struct.Message.html
- #[cfg(feature="methods")]
pub fn download(&self) -> Result<Vec<u8>> {
let hyper = HyperClient::new();
let mut response = hyper.get(&self.url).send()?;
@@ -123,6 +121,50 @@ impl Attachment {
}
impl Channel {
+ /// Marks the channel as being read up to a certain [`Message`].
+ ///
+ /// Refer to the documentation for [`rest::ack_message`] for more
+ /// information.
+ ///
+ /// # Errors
+ ///
+ /// If the `cache` is enabled, returns a
+ /// [`ClientError::InvalidOperationAsBot`] if the current user is a bot
+ /// user.
+ ///
+ /// [`Channel`]: enum.Channel.html
+ /// [`ClientError::InvalidOperationAsBot`]: ../client/enum.ClientError.html#variant.InvalidOperationAsUser
+ /// [`Message`]: struct.Message.html
+ /// [`rest::ack_message`]: rest/fn.ack_message.html
+ pub fn ack<M: Into<MessageId>>(&self, message_id: M) -> Result<()> {
+ #[cfg(feature="cache")]
+ {
+ if CACHE.read().unwrap().user.bot {
+ return Err(Error::Client(ClientError::InvalidOperationAsBot));
+ }
+ }
+
+ self.id().ack(message_id)
+ }
+
+ /// React to a [`Message`] with a custom [`Emoji`] or unicode character.
+ ///
+ /// [`Message::react`] may be a more suited method of reacting in most
+ /// cases.
+ ///
+ /// Requires the [Add Reactions] permission, _if_ the current user is the
+ /// first user to perform a react with a certain emoji.
+ ///
+ /// [`Emoji`]: struct.Emoji.html
+ /// [`Message`]: struct.Message.html
+ /// [`Message::react`]: struct.Message.html#method.react
+ /// [Add Reactions]: permissions/constant.ADD_REACTIONS.html
+ #[inline]
+ pub fn create_reaction<M, R>(&self, message_id: M, reaction_type: R)
+ -> Result<()> where M: Into<MessageId>, R: Into<ReactionType> {
+ self.id().create_reaction(message_id, reaction_type)
+ }
+
#[doc(hidden)]
pub fn decode(value: Value) -> Result<Channel> {
let map = into_map(value)?;
@@ -144,7 +186,6 @@ impl Channel {
/// closest functionality is leaving it.
///
/// [`Group`]: struct.Group.html
- #[cfg(feature="methods")]
pub fn delete(&self) -> Result<()> {
match *self {
Channel::Group(ref group) => {
@@ -161,6 +202,122 @@ impl Channel {
Ok(())
}
+ /// Deletes a [`Message`] given its Id.
+ ///
+ /// Refer to [`Message::delete`] for more information.
+ ///
+ /// Requires the [Manage Messages] permission, if the current user is not
+ /// the author of the message.
+ ///
+ /// (in practice, please do not do this)
+ ///
+ /// [`Message`]: struct.Message.html
+ /// [`Message::delete`]: struct.Message.html#method.delete
+ /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
+ #[inline]
+ pub fn delete_message<M: Into<MessageId>>(&self, message_id: M) -> Result<()> {
+ self.id().delete_message(message_id)
+ }
+
+ /// Deletes all messages by Ids from the given vector in the channel.
+ ///
+ /// The minimum amount of messages is 2 and the maximum amount is 100.
+ ///
+ /// Requires the [Manage Messages] permission.
+ ///
+ /// **Note**: This uses bulk delete endpoint which is not available
+ /// for user accounts.
+ ///
+ /// **Note**: Messages that are older than 2 weeks can't be deleted using
+ /// this method.
+ ///
+ /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
+ #[inline]
+ pub fn delete_messages(&self, message_ids: &[MessageId]) -> Result<()> {
+ self.id().delete_messages(message_ids)
+ }
+
+ /// Deletes all permission overrides in the channel from a member
+ /// or role.
+ ///
+ /// **Note**: Requires the [Manage Channel] permission.
+ ///
+ /// [Manage Channel]: permissions/constant.MANAGE_CHANNELS.html
+ #[inline]
+ pub fn delete_permission(&self, permission_type: PermissionOverwriteType) -> Result<()> {
+ self.id().delete_permission(permission_type)
+ }
+
+ /// Deletes the given [`Reaction`] from the channel.
+ ///
+ /// **Note**: Requires the [Manage Messages] permission, _if_ the current
+ /// user did not perform the reaction.
+ ///
+ /// [`Reaction`]: struct.Reaction.html
+ /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
+ #[inline]
+ pub fn delete_reaction<M, R>(&self, message_id: M, user_id: Option<UserId>, reaction_type: R)
+ -> Result<()> where M: Into<MessageId>, R: Into<ReactionType> {
+ self.id().delete_reaction(message_id, user_id, reaction_type)
+ }
+
+ /// Gets a message from the channel.
+ ///
+ /// Requires the [Read Message History] permission.
+ ///
+ /// [Read Message History]: permission/constant.READ_MESSAGE_HISTORY.html
+ #[inline]
+ pub fn get_message<M: Into<MessageId>>(&self, message_id: M) -> Result<Message> {
+ self.id().get_message(message_id)
+ }
+
+ /// Gets messages from the channel.
+ ///
+ /// Requires the [Read Message History] permission.
+ ///
+ /// # Examples
+ ///
+ /// ```rust,ignore
+ /// use serenity::model::ChannelId;
+ ///
+ /// let messages = channel.get_messages(|g| g
+ /// .before(20)
+ /// .after(100)); // Maximum is 100.
+ /// ```
+ ///
+ /// [Read Message History]: permission/constant.READ_MESSAGE_HISTORY.html
+ #[inline]
+ pub fn get_messages<F>(&self, f: F) -> Result<Vec<Message>>
+ where F: FnOnce(GetMessages) -> GetMessages {
+ self.id().get_messages(f)
+ }
+
+ /// Gets the list of [`User`]s who have reacted to a [`Message`] with a
+ /// certain [`Emoji`].
+ ///
+ /// The default `limit` is `50` - specify otherwise to receive a different
+ /// maximum number of users. The maximum that may be retrieve at a time is
+ /// `100`, if a greater number is provided then it is automatically reduced.
+ ///
+ /// The optional `after` attribute is to retrieve the users after a certain
+ /// user. This is useful for pagination.
+ ///
+ /// **Note**: Requires the [Read Message History] permission.
+ ///
+ /// [`Emoji`]: struct.Emoji.html
+ /// [`Message`]: struct.Message.html
+ /// [`User`]: struct.User.html
+ /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
+ #[inline]
+ pub fn get_reaction_users<M, R, U>(&self,
+ message_id: M,
+ reaction_type: R,
+ limit: Option<u8>,
+ after: Option<U>)
+ -> Result<Vec<User>> where M: Into<MessageId>, R: Into<ReactionType>, U: Into<UserId> {
+ self.id().get_reaction_users(message_id, reaction_type, limit, after)
+ }
+
/// Retrieves the Id of the inner [`Group`], [`GuildChannel`], or
/// [`PrivateChannel`].
///
@@ -191,7 +348,6 @@ impl Channel {
/// [`ClientError::InvalidOperationAsBot`]: ../client/enum.ClientError.html#variant.InvalidOperationAsBot
/// [`Message`]: struct.Message.html
/// [`Search`]: ../utils/builder/struct.Search.html
- #[cfg(feature="methods")]
pub fn search<F>(&self, f: F) -> Result<SearchResult>
where F: FnOnce(Search) -> Search {
#[cfg(feature="cache")]
@@ -201,13 +357,18 @@ impl Channel {
}
}
- let id = match *self {
- Channel::Group(ref group) => group.channel_id.0,
- Channel::Guild(ref channel) => channel.id.0,
- Channel::Private(ref channel) => channel.id.0,
- };
+ self.id().search(f)
+ }
- rest::search_channel_messages(id, f(Search::default()).0)
+ /// Unpins a [`Message`] in the channel given by its Id.
+ ///
+ /// Requires the [Manage Messages] permission.
+ ///
+ /// [`Message`]: struct.Message.html
+ /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
+ #[inline]
+ pub fn unpin<M: Into<MessageId>>(&self, message_id: M) -> Result<()> {
+ self.id().unpin(message_id)
}
}
@@ -236,20 +397,509 @@ impl fmt::Display for Channel {
}
}
+impl ChannelId {
+ /// Marks a [`Channel`] as being read up to a certain [`Message`].
+ ///
+ /// Refer to the documentation for [`rest::ack_message`] for more
+ /// information.
+ ///
+ /// [`Channel`]: enum.Channel.html
+ /// [`Message`]: struct.Message.html
+ /// [`rest::ack_message`]: rest/fn.ack_message.html
+ #[inline]
+ pub fn ack<M: Into<MessageId>>(&self, message_id: M) -> Result<()> {
+ rest::ack_message(self.0, message_id.into().0)
+ }
+
+ /// Broadcasts that the current user is typing to a channel for the next 5
+ /// seconds.
+ ///
+ /// After 5 seconds, another request must be made to continue broadcasting
+ /// that the current user is typing.
+ ///
+ /// This should rarely be used for bots, and should likely only be used for
+ /// signifying that a long-running command is still being executed.
+ ///
+ /// **Note**: Requires the [Send Messages] permission.
+ ///
+ /// # Examples
+ ///
+ /// ```rust,ignore
+ /// use serenity::model::ChannelId;
+ ///
+ /// let _successful = ChannelId(7).broadcast_typing();
+ /// ```
+ ///
+ /// [Send Messages]: permissions/constant.SEND_MESSAGES.html
+ #[inline]
+ pub fn broadcast_typing(&self) -> Result<()> {
+ rest::broadcast_typing(self.0)
+ }
+
+ /// Creates a [permission overwrite][`PermissionOverwrite`] for either a
+ /// single [`Member`] or [`Role`] within the channel.
+ ///
+ /// Refer to the documentation for [`GuildChannel::create_permission`] for
+ /// more information.
+ ///
+ /// Requires the [Manage Channels] permission.
+ ///
+ /// [`GuildChannel::create_permission`]: struct.GuildChannel.html#method.create_permission
+ /// [`Member`]: struct.Member.html
+ /// [`PermissionOverwrite`]: struct.PermissionOverWrite.html
+ /// [`Role`]: struct.Role.html
+ /// [Manage Channels]: permissions/constant.MANAGE_CHANNELS.html
+ pub fn create_permission(&self, target: PermissionOverwrite)
+ -> Result<()> {
+ let (id, kind) = match target.kind {
+ PermissionOverwriteType::Member(id) => (id.0, "member"),
+ PermissionOverwriteType::Role(id) => (id.0, "role"),
+ };
+
+ let map = ObjectBuilder::new()
+ .insert("allow", target.allow.bits())
+ .insert("deny", target.deny.bits())
+ .insert("id", id)
+ .insert("type", kind)
+ .build();
+
+ rest::create_permission(self.0, id, map)
+ }
+
+ /// React to a [`Message`] with a custom [`Emoji`] or unicode character.
+ ///
+ /// [`Message::react`] may be a more suited method of reacting in most
+ /// cases.
+ ///
+ /// Requires the [Add Reactions] permission, _if_ the current user is the
+ /// first user to perform a react with a certain emoji.
+ ///
+ /// [`Emoji`]: struct.Emoji.html
+ /// [`Message`]: struct.Message.html
+ /// [`Message::react`]: struct.Message.html#method.react
+ /// [Add Reactions]: permissions/constant.ADD_REACTIONS.html
+ #[inline]
+ pub fn create_reaction<M, R>(&self, message_id: M, reaction_type: R)
+ -> Result<()> where M: Into<MessageId>, R: Into<ReactionType> {
+ rest::create_reaction(self.0, message_id.into().0, reaction_type.into())
+ }
+
+ /// Deletes this channel, returning the channel on a successful deletion.
+ #[inline]
+ pub fn delete(&self) -> Result<Channel> {
+ rest::delete_channel(self.0)
+ }
+
+ /// Deletes a [`Message`] given its Id.
+ ///
+ /// Refer to [`Message::delete`] for more information.
+ ///
+ /// Requires the [Manage Messages] permission, if the current user is not
+ /// the author of the message.
+ ///
+ /// (in practice, please do not do this)
+ ///
+ /// [`Message`]: struct.Message.html
+ /// [`Message::delete`]: struct.Message.html#method.delete
+ /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
+ #[inline]
+ pub fn delete_message<M: Into<MessageId>>(&self, message_id: M) -> Result<()> {
+ rest::delete_message(self.0, message_id.into().0)
+ }
+
+ /// Deletes all messages by Ids from the given vector in the given channel.
+ ///
+ /// Refer to the documentation for [`Channel::delete_messages`] for more
+ /// information.
+ ///
+ /// Requires the [Manage Messages] permission.
+ ///
+ /// **Note**: This uses bulk delete endpoint which is not available
+ /// for user accounts.
+ ///
+ /// **Note**: Messages that are older than 2 weeks can't be deleted using this method.
+ ///
+ /// [`Channel::delete_messages`]: enum.Channel.html#method.delete_messages
+ /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
+ pub fn delete_messages(&self, message_ids: &[MessageId]) -> Result<()> {
+ let ids = message_ids.into_iter()
+ .map(|message_id| message_id.0)
+ .collect::<Vec<u64>>();
+
+ let map = ObjectBuilder::new().insert("messages", ids).build();
+
+ rest::delete_messages(self.0, map)
+ }
+
+ /// Deletes all permission overrides in the channel from a member or role.
+ ///
+ /// **Note**: Requires the [Manage Channel] permission.
+ ///
+ /// [Manage Channel]: permissions/constant.MANAGE_CHANNELS.html
+ pub fn delete_permission(&self, permission_type: PermissionOverwriteType) -> Result<()> {
+ rest::delete_permission(self.0, match permission_type {
+ PermissionOverwriteType::Member(id) => id.0,
+ PermissionOverwriteType::Role(id) => id.0,
+ })
+ }
+
+ /// Deletes the given [`Reaction`] from the channel.
+ ///
+ /// **Note**: Requires the [Manage Messages] permission, _if_ the current
+ /// user did not perform the reaction.
+ ///
+ /// [`Reaction`]: struct.Reaction.html
+ /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
+ pub fn delete_reaction<M, R>(&self, message_id: M, user_id: Option<UserId>, reaction_type: R)
+ -> Result<()> where M: Into<MessageId>, R: Into<ReactionType> {
+ rest::delete_reaction(self.0,
+ message_id.into().0,
+ user_id.map(|uid| uid.0),
+ reaction_type.into())
+ }
+
+
+ /// Edits the settings of a [`Channel`], optionally setting new values.
+ ///
+ /// Refer to `EditChannel`'s documentation for its methods.
+ ///
+ /// Requires the [Manage Channel] permission.
+ ///
+ /// # Examples
+ ///
+ /// Change a voice channel's name and bitrate:
+ ///
+ /// ```rust,ignore
+ /// context.edit_channel(channel_id, |c| c
+ /// .name("test")
+ /// .bitrate(64000));
+ /// ```
+ ///
+ /// # Errors
+ ///
+ /// Returns a [`ClientError::NoChannelId`] if the current context is not
+ /// related to a channel.
+ ///
+ /// [`Channel`]: enum.Channel.html
+ /// [`ClientError::NoChannelId`]: ../client/enum.ClientError.html#variant.NoChannelId
+ #[inline]
+ pub fn edit<F: FnOnce(EditChannel) -> EditChannel>(&self, f: F) -> Result<GuildChannel> {
+ rest::edit_channel(self.0, f(EditChannel::default()).0.build())
+ }
+
+ /// Edits a [`Message`] in the channel given its Id.
+ ///
+ /// Pass an empty string (`""`) to `text` if you are editing a message with
+ /// an embed or file but no content. Otherwise, `text` must be given.
+ ///
+ /// **Note**: Requires that the current user be the author of the message.
+ ///
+ /// # Errors
+ ///
+ /// Returns a [`ClientError::NoChannelId`] if the current context is not
+ /// related to a channel.
+ ///
+ /// [`ClientError::NoChannelId`]: ../client/enum.ClientError.html#variant.NoChannelId
+ /// [`Message`]: struct.Message.html
+ pub fn edit_message<F, M>(&self, message_id: M, text: &str, f: F) -> Result<Message>
+ where F: FnOnce(CreateEmbed) -> CreateEmbed, M: Into<MessageId> {
+ let mut map = ObjectBuilder::new().insert("content", text);
+
+ let embed = f(CreateEmbed::default()).0;
+
+ if embed.len() > 1 {
+ map = map.insert("embed", Value::Object(embed));
+ }
+
+ rest::edit_message(self.0, message_id.into().0, map.build())
+ }
+
+ /// Search the cache for the channel with the Id.
+ #[cfg(feature="cache")]
+ pub fn find(&self) -> Option<Channel> {
+ CACHE.read().unwrap().get_channel(*self).map(|x| x.clone_inner())
+ }
+
+ /// Search the cache for the channel. If it can't be found, the channel is
+ /// requested over REST.
+ pub fn get(&self) -> Result<Channel> {
+ #[cfg(feature="cache")]
+ {
+ if let Some(channel) = CACHE.read().unwrap().get_channel(*self) {
+ return Ok(channel.clone_inner());
+ }
+ }
+
+ rest::get_channel(self.0)
+ }
+
+ /// Gets all of the channel's invites.
+ ///
+ /// Requires the [Manage Channels] permission.
+ /// [Manage Channels]: permissions/constant.MANAGE_CHANNELS.html
+ #[inline]
+ pub fn get_invites(&self) -> Result<Vec<RichInvite>> {
+ rest::get_channel_invites(self.0)
+ }
+
+ /// Gets a message from the channel.
+ ///
+ /// Requires the [Read Message History] permission.
+ ///
+ /// [Read Message History]: permission/constant.READ_MESSAGE_HISTORY.html
+ #[inline]
+ pub fn get_message<M: Into<MessageId>>(&self, message_id: M) -> Result<Message> {
+ rest::get_message(self.0, message_id.into().0)
+ }
+
+ /// Gets messages from the channel.
+ ///
+ /// Refer to [`Channel::get_messages`] for more information.
+ ///
+ /// Requires the [Read Message History] permission.
+ ///
+ /// [`Channel::get_messages`]: enum.Channel.html#method.get_messages
+ /// [Read Message History]: permission/constant.READ_MESSAGE_HISTORY.html
+ pub fn get_messages<F>(&self, f: F) -> Result<Vec<Message>>
+ where F: FnOnce(GetMessages) -> GetMessages {
+ let mut map = f(GetMessages::default()).0;
+ let mut query = format!("?limit={}", map.remove("limit").unwrap_or(50));
+
+ if let Some(after) = map.remove("after") {
+ write!(query, "&after={}", after)?;
+ } else if let Some(around) = map.remove("around") {
+ write!(query, "&around={}", around)?;
+ } else if let Some(before) = map.remove("before") {
+ write!(query, "&before={}", before)?;
+ }
+
+ rest::get_messages(self.0, &query)
+ }
+
+ /// Gets the list of [`User`]s who have reacted to a [`Message`] with a
+ /// certain [`Emoji`].
+ ///
+ /// Refer to [`Channel::get_reaction_users`] for more information.
+ ///
+ /// **Note**: Requires the [Read Message History] permission.
+ ///
+ /// [`Channel::get_reaction_users`]: enum.Channel.html#variant.get_reaction_users
+ /// [`Emoji`]: struct.Emoji.html
+ /// [`Message`]: struct.Message.html
+ /// [`User`]: struct.User.html
+ /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
+ pub fn get_reaction_users<M, R, U>(&self,
+ message_id: M,
+ reaction_type: R,
+ limit: Option<u8>,
+ after: Option<U>)
+ -> Result<Vec<User>> where M: Into<MessageId>, R: Into<ReactionType>, U: Into<UserId> {
+ let limit = limit.map_or(50, |x| if x > 100 { 100 } else { x });
+
+ rest::get_reaction_users(self.0,
+ message_id.into().0,
+ reaction_type.into(),
+ limit,
+ after.map(|u| u.into().0))
+ }
+
+ /// Pins a [`Message`] to the channel.
+ #[inline]
+ pub fn pin<M: Into<MessageId>>(&self, message_id: M) -> Result<()> {
+ rest::pin_message(self.0, message_id.into().0)
+ }
+
+ /// Gets the list of [`Message`]s which are pinned to the channel.
+ #[inline]
+ pub fn pins(&self) -> Result<Vec<Message>> {
+ rest::get_pins(self.0)
+ }
+
+ /// Searches the channel's messages by providing query parameters via the
+ /// search builder.
+ ///
+ /// Refer to the documentation for the [`Search`] builder for restrictions
+ /// and defaults parameters, as well as potentially advanced usage.
+ ///
+ /// **Note**: Bot users can not search.
+ ///
+ /// # Examples
+ ///
+ /// Refer to the [`Search`] builder's documentation for examples,
+ /// specifically the section on [searching a channel][search channel].
+ ///
+ /// [`Search`]: ../utils/builder/struct.Search.html
+ #[inline]
+ pub fn search<F: FnOnce(Search) -> Search>(&self, f: F) -> Result<SearchResult> {
+ rest::search_channel_messages(self.0, f(Search::default()).0)
+ }
+
+ /// Sends a file along with optional message contents. The filename _must_
+ /// be specified.
+ ///
+ /// Message contents may be passed by using the [`CreateMessage::content`]
+ /// method.
+ ///
+ /// An embed can _not_ be sent when sending a file. If you set one, it will
+ /// be automatically removed.
+ ///
+ /// Requires the [Attach Files] and [Send Messages] permissions are required.
+ ///
+ /// **Note**: Message contents must be under 2000 unicode code points.
+ ///
+ /// # Errors
+ ///
+ /// If the content of the message is over the above limit, then a
+ /// [`ClientError::MessageTooLong`] will be returned, containing the number
+ /// of unicode code points over the limit.
+ ///
+ /// [`ClientError::MessageTooLong`]: ../client/enum.ClientError.html#variant.MessageTooLong
+ /// [`CreateMessage::content`]: ../utils/builder/struct.CreateMessage.html#method.content
+ /// [`GuildChannel`]: struct.GuildChannel.html
+ /// [Attach Files]: permissions/constant.ATTACH_FILES.html
+ /// [Send Messages]: permissions/constant.SEND_MESSAGES.html
+ pub fn send_file<F, R>(&self, file: R, filename: &str, f: F) -> Result<Message>
+ where F: FnOnce(CreateMessage) -> CreateMessage, R: Read {
+ let mut map = f(CreateMessage::default()).0;
+
+ if let Some(content) = map.get("content") {
+ if let Value::String(ref content) = *content {
+ if let Some(length_over) = Message::overflow_length(content) {
+ return Err(Error::Client(ClientError::MessageTooLong(length_over)));
+ }
+ }
+ }
+
+ let _ = map.remove("embed");
+
+ rest::send_file(self.0, file, filename, map)
+ }
+
+ /// Sends a message to the channel.
+ ///
+ /// Refer to the documentation for [`CreateMessage`] for more information
+ /// regarding message restrictions and requirements.
+ ///
+ /// Requires the [Send Messages] permission is required.
+ ///
+ /// **Note**: Message contents must be under 2000 unicode code points.
+ ///
+ /// # Errors
+ ///
+ /// Returns a [`ClientError::MessageTooLong`] if the content of the message
+ /// is over the above limit, containing the number of unicode code points
+ /// over the limit.
+ ///
+ /// [`Channel`]: enum.Channel.html
+ /// [`ClientError::MessageTooLong`]: ../client/enum.ClientError.html#variant.MessageTooLong
+ /// [`CreateMessage`]: ../utils/builder/struct.CreateMessage.html
+ /// [Send Messages]: permissions/constant.SEND_MESSAGES.html
+ pub fn send_message<F>(&self, f: F) -> Result<Message>
+ where F: FnOnce(CreateMessage) -> CreateMessage {
+ let map = f(CreateMessage::default()).0;
+
+ if let Some(content) = map.get(&"content".to_owned()) {
+ if let Value::String(ref content) = *content {
+ if let Some(length_over) = Message::overflow_length(content) {
+ return Err(Error::Client(ClientError::MessageTooLong(length_over)));
+ }
+ }
+ }
+
+ rest::send_message(self.0, Value::Object(map))
+ }
+
+ /// Unpins a [`Message`] in the channel given by its Id.
+ ///
+ /// Requires the [Manage Messages] permission.
+ ///
+ /// [`Message`]: struct.Message.html
+ /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
+ #[inline]
+ pub fn unpin<M: Into<MessageId>>(&self, message_id: M) -> Result<()> {
+ rest::unpin_message(self.0, message_id.into().0)
+ }
+
+ /// Retrieves the channel's webhooks.
+ ///
+ /// **Note**: Requires the [Manage Webhooks] permission.
+ ///
+ /// [Manage Webhooks]: permissions/constant.MANAGE_WEBHOOKS.html
+ #[inline]
+ pub fn webhooks(&self) -> Result<Vec<Webhook>> {
+ rest::get_channel_webhooks(self.0)
+ }
+}
+
+impl From<Channel> for ChannelId {
+ /// Gets the Id of a `Channel`.
+ fn from(channel: Channel) -> ChannelId {
+ match channel {
+ Channel::Group(group) => group.channel_id,
+ Channel::Guild(channel) => channel.id,
+ Channel::Private(channel) => channel.id,
+ }
+ }
+}
+
+impl From<PrivateChannel> for ChannelId {
+ /// Gets the Id of a private channel.
+ fn from(private_channel: PrivateChannel) -> ChannelId {
+ private_channel.id
+ }
+}
+
+impl From<GuildChannel> for ChannelId {
+ /// Gets the Id of a guild channel.
+ fn from(public_channel: GuildChannel) -> ChannelId {
+ public_channel.id
+ }
+}
+
+impl fmt::Display for ChannelId {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(&self.0, f)
+ }
+}
+
impl Embed {
/// Creates a fake Embed, giving back a `serde_json` map.
///
/// This should only be useful in conjunction with [`Webhook::execute`].
///
/// [`Webhook::execute`]: struct.Webhook.html
- #[cfg(feature="methods")]
- #[inline(always)]
+ #[inline]
pub fn fake<F>(f: F) -> Value where F: FnOnce(CreateEmbed) -> CreateEmbed {
Value::Object(f(CreateEmbed::default()).0)
}
}
impl Group {
+ /// Marks the group as being read up to a certain [`Message`].
+ ///
+ /// Refer to the documentation for [`rest::ack_message`] for more
+ /// information.
+ ///
+ /// # Errors
+ ///
+ /// If the `cache` is enabled, returns a
+ /// [`ClientError::InvalidOperationAsBot`] if the current user is a bot
+ /// user.
+ ///
+ /// [`ClientError::InvalidOperationAsBot`]: ../client/enum.ClientError.html#variant.InvalidOperationAsUser
+ /// [`Message`]: struct.Message.html
+ /// [`rest::ack_message`]: rest/fn.ack_message.html
+ pub fn ack<M: Into<MessageId>>(&self, message_id: M) -> Result<()> {
+ #[cfg(feature="cache")]
+ {
+ if CACHE.read().unwrap().user.bot {
+ return Err(Error::Client(ClientError::InvalidOperationAsBot));
+ }
+ }
+
+ self.channel_id.ack(message_id)
+ }
+
/// Adds the given user to the group. If the user is already in the group,
/// then nothing is done.
///
@@ -259,7 +909,6 @@ impl Group {
/// user.
///
/// [`rest::add_group_recipient`]: ../client/rest/fn.add_group_recipient.html
- #[cfg(feature="methods")]
pub fn add_recipient<U: Into<UserId>>(&self, user: U) -> Result<()> {
let user = user.into();
@@ -272,43 +921,113 @@ impl Group {
}
/// Broadcasts that the current user is typing in the group.
- #[cfg(feature="methods")]
+ #[inline]
pub fn broadcast_typing(&self) -> Result<()> {
- rest::broadcast_typing(self.channel_id.0)
+ self.channel_id.broadcast_typing()
}
- /// Deletes multiple messages in the group.
+ /// React to a [`Message`] with a custom [`Emoji`] or unicode character.
///
- /// Refer to
- /// [`Context::delete_messages`] for more information.
+ /// [`Message::react`] may be a more suited method of reacting in most
+ /// cases.
///
- /// **Note**: Only 2 to 100 messages may be deleted in a single request.
+ /// Requires the [Add Reactions] permission, _if_ the current user is the
+ /// first user to perform a react with a certain emoji.
///
- /// **Note**: Messages that are older than 2 weeks can't be deleted using this method.
+ /// [`Emoji`]: struct.Emoji.html
+ /// [`Message`]: struct.Message.html
+ /// [`Message::react`]: struct.Message.html#method.react
+ /// [Add Reactions]: permissions/constant.ADD_REACTIONS.html
+ #[inline]
+ pub fn create_reaction<M, R>(&self, message_id: M, reaction_type: R)
+ -> Result<()> where M: Into<MessageId>, R: Into<ReactionType> {
+ self.channel_id.create_reaction(message_id, reaction_type)
+ }
+
+ /// Deletes all messages by Ids from the given vector in the channel.
///
- /// # Errors
+ /// Refer to [`Channel::delete_messages`] for more information.
///
- /// Returns a
- /// [`ClientError::DeleteMessageDaysAmount`] if the number of messages to
- /// delete is not within the valid range.
+ /// Requires the [Manage Messages] permission.
///
- /// [`ClientError::DeleteMessageDaysAmount`]: ../client/enum.ClientError.html#variant.DeleteMessageDaysAmount
- /// [`Context::delete_messages`]: ../client/struct.Context.html#delete_messages
- #[cfg(feature="methods")]
+ /// **Note**: This uses bulk delete endpoint which is not available
+ /// for user accounts.
+ ///
+ /// **Note**: Messages that are older than 2 weeks can't be deleted using
+ /// this method.
+ ///
+ /// [`Channel::delete_messages`]: enum.Channel.html#method.delete_messages
+ /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
+ #[inline]
pub fn delete_messages(&self, message_ids: &[MessageId]) -> Result<()> {
- if message_ids.len() < 2 || message_ids.len() > 100 {
- return Err(Error::Client(ClientError::BulkDeleteAmount));
- }
+ self.channel_id.delete_messages(message_ids)
+ }
- let ids: Vec<u64> = message_ids.into_iter()
- .map(|message_id| message_id.0)
- .collect();
+ /// Deletes all permission overrides in the channel from a member
+ /// or role.
+ ///
+ /// **Note**: Requires the [Manage Channel] permission.
+ ///
+ /// [Manage Channel]: permissions/constant.MANAGE_CHANNELS.html
+ #[inline]
+ pub fn delete_permission(&self, permission_type: PermissionOverwriteType) -> Result<()> {
+ self.channel_id.delete_permission(permission_type)
+ }
- let map = ObjectBuilder::new()
- .insert("messages", ids)
- .build();
+ /// Deletes the given [`Reaction`] from the channel.
+ ///
+ /// **Note**: Requires the [Manage Messages] permission, _if_ the current
+ /// user did not perform the reaction.
+ ///
+ /// [`Reaction`]: struct.Reaction.html
+ /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
+ #[inline]
+ pub fn delete_reaction<M, R>(&self, message_id: M, user_id: Option<UserId>, reaction_type: R)
+ -> Result<()> where M: Into<MessageId>, R: Into<ReactionType> {
+ self.channel_id.delete_reaction(message_id, user_id, reaction_type)
+ }
- rest::delete_messages(self.channel_id.0, map)
+ /// Gets a message from the channel.
+ ///
+ /// Requires the [Read Message History] permission.
+ ///
+ /// [Read Message History]: permission/constant.READ_MESSAGE_HISTORY.html
+ #[inline]
+ pub fn get_message<M: Into<MessageId>>(&self, message_id: M) -> Result<Message> {
+ self.channel_id.get_message(message_id)
+ }
+
+ /// Gets messages from the channel.
+ ///
+ /// Requires the [Read Message History] permission.
+ ///
+ /// [Read Message History]: permission/constant.READ_MESSAGE_HISTORY.html
+ #[inline]
+ pub fn get_messages<F>(&self, f: F) -> Result<Vec<Message>>
+ where F: FnOnce(GetMessages) -> GetMessages {
+ self.channel_id.get_messages(f)
+ }
+
+ /// Gets the list of [`User`]s who have reacted to a [`Message`] with a
+ /// certain [`Emoji`].
+ ///
+ /// Refer to [`Channel::get_reaction_users`] for more information.
+ ///
+ /// **Note**: Requires the [Read Message History] permission.
+ ///
+ /// [`Channel::get_reaction_users`]: enum.Channel.html#variant.get_reaction_users
+ /// [`Emoji`]: struct.Emoji.html
+ /// [`Message`]: struct.Message.html
+ /// [`User`]: struct.User.html
+ /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
+ #[inline]
+ pub fn get_reaction_users<M, R, U>(&self,
+ message_id: M,
+ reaction_type: R,
+ limit: Option<u8>,
+ after: Option<U>)
+ -> Result<Vec<User>> where M: Into<MessageId>, R: Into<ReactionType>, U: Into<UserId> {
+ self.channel_id.get_reaction_users(message_id, reaction_type, limit, after)
}
/// Returns the formatted URI of the group's icon if one exists.
@@ -318,7 +1037,7 @@ impl Group {
}
/// Leaves the group.
- #[cfg(feature="methods")]
+ #[inline]
pub fn leave(&self) -> Result<Group> {
rest::leave_group(self.channel_id.0)
}
@@ -347,16 +1066,15 @@ impl Group {
}
/// Retrieves the list of messages that have been pinned in the group.
- #[cfg(feature="methods")]
+ #[inline]
pub fn pins(&self) -> Result<Vec<Message>> {
- rest::get_pins(self.channel_id.0)
+ self.channel_id.pins()
}
/// Removes a recipient from the group. If the recipient is already not in
/// the group, then nothing is done.
///
/// **Note**: This is only available to the group owner.
- #[cfg(feature="methods")]
pub fn remove_recipient<U: Into<UserId>>(&self, user: U) -> Result<()> {
let user = user.into();
@@ -384,10 +1102,10 @@ impl Group {
/// [`ClientError::InvalidOperationAsBot`]: ../client/enum.ClientError.html#variant.InvalidOperationAsBot
/// [`Message`]: struct.Message.html
/// [`Search`]: ../utils/builder/struct.Search.html
- #[cfg(feature="methods")]
+ #[inline]
pub fn search<F>(&self, f: F) -> Result<SearchResult>
where F: FnOnce(Search) -> Search {
- rest::search_channel_messages(self.channel_id.0, f(Search::default()).0)
+ self.channel_id.search(f)
}
/// Sends a message to the group with the given content.
@@ -397,19 +1115,50 @@ impl Group {
/// **Note**: Requires the [Send Messages] permission.
///
/// [Send Messages]: permissions/constant.SEND_MESSAGES.html
- #[cfg(feature="methods")]
+ #[inline]
pub fn send_message(&self, content: &str) -> Result<Message> {
- let map = ObjectBuilder::new()
- .insert("content", content)
- .insert("nonce", "")
- .insert("tts", false)
- .build();
+ self.channel_id.send_message(|m| m.content(content))
+ }
- rest::send_message(self.channel_id.0, map)
+ /// Unpins a [`Message`] in the channel given by its Id.
+ ///
+ /// Requires the [Manage Messages] permission.
+ ///
+ /// [`Message`]: struct.Message.html
+ /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
+ #[inline]
+ pub fn unpin<M: Into<MessageId>>(&self, message_id: M) -> Result<()> {
+ self.channel_id.unpin(message_id.into().0)
}
}
impl Message {
+ /// Marks the [`Channel`] as being read up to the message.
+ ///
+ /// Refer to the documentation for [`rest::ack_message`] for more
+ /// information.
+ ///
+ /// # Errors
+ ///
+ /// If the `cache` is enabled, returns a
+ /// [`ClientError::InvalidOperationAsBot`] if the current user is a bot
+ /// user.
+ ///
+ /// [`Channel`]: enum.Channel.html
+ /// [`ClientError::InvalidOperationAsBot`]: ../client/enum.ClientError.html#variant.InvalidOperationAsUser
+ /// [`Message`]: struct.Message.html
+ /// [`rest::ack_message`]: rest/fn.ack_message.html
+ pub fn ack<M: Into<MessageId>>(&self) -> Result<()> {
+ #[cfg(feature="cache")]
+ {
+ if CACHE.read().unwrap().user.bot {
+ return Err(Error::Client(ClientError::InvalidOperationAsBot));
+ }
+ }
+
+ self.channel_id.ack(self.id)
+ }
+
/// Deletes the message.
///
/// **Note**: The logged in user must either be the author of the message or
@@ -424,7 +1173,6 @@ impl Message {
/// [`ClientError::InvalidPermissions`]: ../client/enum.ClientError.html#variant.InvalidPermissions
/// [`ClientError::InvalidUser`]: ../client/enum.ClientError.html#variant.InvalidUser
/// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
- #[cfg(feature="methods")]
pub fn delete(&self) -> Result<()> {
#[cfg(feature="cache")]
{
@@ -437,7 +1185,7 @@ impl Message {
}
}
- rest::delete_message(self.channel_id.0, self.id.0)
+ self.channel_id.delete_message(self.id)
}
/// Deletes all of the [`Reaction`]s associated with the message.
@@ -453,7 +1201,6 @@ impl Message {
/// [`ClientError::InvalidPermissions`]: ../client/enum.ClientError.html#variant.InvalidPermissions
/// [`Reaction`]: struct.Reaction.html
/// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
- #[cfg(feature="methods")]
pub fn delete_reactions(&self) -> Result<()> {
#[cfg(feature="cache")]
{
@@ -490,8 +1237,7 @@ impl Message {
/// over the limit.
///
/// [`ClientError::InvalidUser`]: ../client/enum.ClientError.html#variant.InvalidUser
- /// [`ClientError::MessageTooLong`]: enum.ClientError.html#variant.MessageTooLong
- #[cfg(feature="methods")]
+ /// [`ClientError::MessageTooLong`]: ../client/enum.ClientError.html#variant.MessageTooLong
pub fn edit<F>(&mut self, new_content: &str, embed: F) -> Result<()>
where F: FnOnce(CreateEmbed) -> CreateEmbed {
if let Some(length_over) = Message::overflow_length(new_content) {
@@ -525,7 +1271,7 @@ impl Message {
/// Returns message content, but with user and role mentions replaced with
/// names and everyone/here mentions cancelled.
- #[cfg(all(feature="cache", feature="methods"))]
+ #[cfg(feature="cache")]
pub fn content_safe(&self) -> String {
let mut result = self.content.clone();
@@ -550,12 +1296,34 @@ impl Message {
.replace("@here", "@\u{200B}here")
}
+ /// Gets the list of [`User`]s who have reacted to a [`Message`] with a
+ /// certain [`Emoji`].
+ ///
+ /// The default `limit` is `50` - specify otherwise to receive a different
+ /// maximum number of users. The maximum that may be retrieve at a time is
+ /// `100`, if a greater number is provided then it is automatically reduced.
+ ///
+ /// The optional `after` attribute is to retrieve the users after a certain
+ /// user. This is useful for pagination.
+ ///
+ /// **Note**: Requires the [Read Message History] permission.
+ ///
+ /// [`Emoji`]: struct.Emoji.html
+ /// [`Message`]: struct.Message.html
+ /// [`User`]: struct.User.html
+ /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
+ #[inline]
+ pub fn get_reaction_users<R, U>(&self, reaction_type: R, limit: Option<u8>, after: Option<U>)
+ -> Result<Vec<User>> where R: Into<ReactionType>, U: Into<UserId> {
+ self.id.get_reaction_users(self.channel_id, reaction_type, limit, after)
+ }
+
/// Retrieves the Id of the guild that the message was sent in, if sent in
/// one.
///
/// Returns `None` if the channel data or guild data does not exist in the
/// cache.
- #[cfg(all(feature="cache", feature="methods"))]
+ #[cfg(feature="cache")]
pub fn guild_id(&self) -> Option<GuildId> {
match CACHE.read().unwrap().get_channel(self.channel_id) {
Some(ChannelRef::Guild(channel)) => Some(channel.guild_id),
@@ -564,7 +1332,7 @@ impl Message {
}
/// True if message was sent using direct messages.
- #[cfg(all(feature="cache", feature="methods"))]
+ #[cfg(feature="cache")]
pub fn is_private(&self) -> bool {
match CACHE.read().unwrap().get_channel(self.channel_id) {
Some(ChannelRef::Group(_)) | Some(ChannelRef::Private(_)) => true,
@@ -603,7 +1371,6 @@ impl Message {
///
/// [`ClientError::InvalidPermissions`]: ../client/enum.ClientError.html#variant.InvalidPermissions
/// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
- #[cfg(feature="methods")]
pub fn pin(&self) -> Result<()> {
#[cfg(feature="cache")]
{
@@ -614,7 +1381,7 @@ impl Message {
}
}
- rest::pin_message(self.channel_id.0, self.id.0)
+ self.channel_id.pin(self.id.0)
}
/// React to the message with a custom [`Emoji`] or unicode character.
@@ -631,7 +1398,6 @@ impl Message {
/// [`Emoji`]: struct.Emoji.html
/// [Add Reactions]: permissions/constant.ADD_REACTIONS.html
/// [permissions]: permissions
- #[cfg(feature="methods")]
pub fn react<R: Into<ReactionType>>(&self, reaction_type: R) -> Result<()> {
#[cfg(feature="cache")]
{
@@ -667,9 +1433,8 @@ impl Message {
/// over the limit.
///
/// [`ClientError::InvalidPermissions`]: ../client/enum.ClientError.html#variant.InvalidPermissions
- /// [`ClientError::MessageTooLong`]: enum.ClientError.html#variant.MessageTooLong
+ /// [`ClientError::MessageTooLong`]: ../client/enum.ClientError.html#variant.MessageTooLong
/// [Send Messages]: permissions/constant.SEND_MESSAGES.html
- #[cfg(feature="methods")]
pub fn reply(&self, content: &str) -> Result<Message> {
if let Some(length_over) = Message::overflow_length(content) {
return Err(Error::Client(ClientError::MessageTooLong(length_over)));
@@ -709,7 +1474,6 @@ impl Message {
///
/// [`ClientError::InvalidPermissions`]: ../client/enum.ClientError.html#variant.InvalidPermissions
/// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
- #[cfg(feature="methods")]
pub fn unpin(&self) -> Result<()> {
#[cfg(feature="cache")]
{
@@ -724,6 +1488,46 @@ impl Message {
}
}
+impl MessageId {
+ /// Gets the list of [`User`]s who have reacted to a [`Message`] with a
+ /// certain [`Emoji`].
+ ///
+ /// The default `limit` is `50` - specify otherwise to receive a different
+ /// maximum number of users. The maximum that may be retrieve at a time is
+ /// `100`, if a greater number is provided then it is automatically reduced.
+ ///
+ /// The optional `after` attribute is to retrieve the users after a certain
+ /// user. This is useful for pagination.
+ ///
+ /// **Note**: Requires the [Read Message History] permission.
+ ///
+ /// [`Emoji`]: struct.Emoji.html
+ /// [`Message`]: struct.Message.html
+ /// [`User`]: struct.User.html
+ /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
+ pub fn get_reaction_users<C, R, U>(&self,
+ channel_id: C,
+ reaction_type: R,
+ limit: Option<u8>,
+ after: Option<U>)
+ -> Result<Vec<User>> where C: Into<ChannelId>, R: Into<ReactionType>, U: Into<UserId> {
+ let limit = limit.map_or(50, |x| if x > 100 { 100 } else { x });
+
+ rest::get_reaction_users(channel_id.into().0,
+ self.0,
+ reaction_type.into(),
+ limit,
+ after.map(|u| u.into().0))
+ }
+}
+
+impl From<Message> for MessageId {
+ /// Gets the Id of a `Message`.
+ fn from(message: Message) -> MessageId {
+ message.id
+ }
+}
+
impl PermissionOverwrite {
#[doc(hidden)]
pub fn decode(value: Value) -> Result<PermissionOverwrite> {
@@ -745,12 +1549,53 @@ impl PermissionOverwrite {
}
impl PrivateChannel {
+ /// Marks the channel as being read up to a certain [`Message`].
+ ///
+ /// Refer to the documentation for [`rest::ack_message`] for more
+ /// information.
+ ///
+ /// # Errors
+ ///
+ /// If the `cache` is enabled, returns a
+ /// [`ClientError::InvalidOperationAsBot`] if the current user is a bot
+ /// user.
+ ///
+ /// [`ClientError::InvalidOperationAsBot`]: ../client/enum.ClientError.html#variant.InvalidOperationAsUser
+ /// [`Message`]: struct.Message.html
+ /// [`rest::ack_message`]: rest/fn.ack_message.html
+ pub fn ack<M: Into<MessageId>>(&self, message_id: M) -> Result<()> {
+ #[cfg(feature="cache")]
+ {
+ if CACHE.read().unwrap().user.bot {
+ return Err(Error::Client(ClientError::InvalidOperationAsBot));
+ }
+ }
+
+ rest::ack_message(self.id.0, message_id.into().0)
+ }
+
/// Broadcasts that the current user is typing to the recipient.
- #[cfg(feature="methods")]
pub fn broadcast_typing(&self) -> Result<()> {
rest::broadcast_typing(self.id.0)
}
+ /// React to a [`Message`] with a custom [`Emoji`] or unicode character.
+ ///
+ /// [`Message::react`] may be a more suited method of reacting in most
+ /// cases.
+ ///
+ /// Requires the [Add Reactions] permission, _if_ the current user is the
+ /// first user to perform a react with a certain emoji.
+ ///
+ /// [`Emoji`]: struct.Emoji.html
+ /// [`Message`]: struct.Message.html
+ /// [`Message::react`]: struct.Message.html#method.react
+ /// [Add Reactions]: permissions/constant.ADD_REACTIONS.html
+ pub fn create_reaction<M, R>(&self, message_id: M, reaction_type: R)
+ -> Result<()> where M: Into<MessageId>, R: Into<ReactionType> {
+ self.id.create_reaction(message_id, reaction_type)
+ }
+
#[doc(hidden)]
pub fn decode(value: Value) -> Result<PrivateChannel> {
let mut map = into_map(value)?;
@@ -769,50 +1614,111 @@ impl PrivateChannel {
/// Deletes the channel. This does not delete the contents of the channel,
/// and is equivalent to closing a private channel on the client, which can
/// be re-opened.
- #[cfg(feature="methods")]
+ #[inline]
pub fn delete(&self) -> Result<Channel> {
- rest::delete_channel(self.id.0)
+ self.id.delete()
}
- /// Deletes the given message Ids from the private channel.
+ /// Deletes all messages by Ids from the given vector in the channel.
+ ///
+ /// Refer to [`Channel::delete_messages`] for more information.
///
- /// **Note** This method is only available to bot users and they can't
- /// delete their recipient's messages.
+ /// Requires the [Manage Messages] permission.
+ ///
+ /// **Note**: This uses bulk delete endpoint which is not available
+ /// for user accounts.
///
/// **Note**: Messages that are older than 2 weeks can't be deleted using
/// this method.
///
- /// # Errors
+ /// [`Channel::delete_messages`]: enum.Channel.html#method.delete_messages
+ /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
+ #[inline]
+ pub fn delete_messages(&self, message_ids: &[MessageId]) -> Result<()> {
+ self.id.delete_messages(message_ids)
+ }
+
+ /// Deletes all permission overrides in the channel from a member
+ /// or role.
///
- /// If the `cache` is enabled, then returns a
- /// [`ClientError::InvalidUser`] if the current user is not a bot user.
+ /// **Note**: Requires the [Manage Channel] permission.
///
- /// [`ClientError::InvalidUser`]: ../client/enum.ClientError.html#variant.InvalidOperationAsUser
- #[cfg(feature="methods")]
- pub fn delete_messages(&self, message_ids: &[MessageId]) -> Result<()> {
- #[cfg(feature="cache")]
- {
- if !CACHE.read().unwrap().user.bot {
- return Err(Error::Client(ClientError::InvalidOperationAsUser));
- }
- }
+ /// [Manage Channel]: permissions/constant.MANAGE_CHANNELS.html
+ #[inline]
+ pub fn delete_permission(&self, permission_type: PermissionOverwriteType) -> Result<()> {
+ self.id.delete_permission(permission_type)
+ }
- let ids: Vec<u64> = message_ids.into_iter()
- .map(|message_id| message_id.0)
- .collect();
+ /// Deletes the given [`Reaction`] from the channel.
+ ///
+ /// **Note**: Requires the [Manage Messages] permission, _if_ the current
+ /// user did not perform the reaction.
+ ///
+ /// [`Reaction`]: struct.Reaction.html
+ /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
+ #[inline]
+ pub fn delete_reaction<M, R>(&self, message_id: M, user_id: Option<UserId>, reaction_type: R)
+ -> Result<()> where M: Into<MessageId>, R: Into<ReactionType> {
+ self.id.delete_reaction(message_id, user_id, reaction_type)
+ }
- let map = ObjectBuilder::new()
- .insert("messages", ids)
- .build();
+ /// Gets a message from the channel.
+ ///
+ /// Requires the [Read Message History] permission.
+ ///
+ /// [Read Message History]: permission/constant.READ_MESSAGE_HISTORY.html
+ #[inline]
+ pub fn get_message<M: Into<MessageId>>(&self, message_id: M) -> Result<Message> {
+ self.id.get_message(message_id)
+ }
+
+ /// Gets messages from the channel.
+ ///
+ /// Refer to [`Channel::get_messages`] for more information.
+ ///
+ /// Requires the [Read Message History] permission.
+ ///
+ /// [`Channel::get_messages`]: enum.Channel.html#method.get_messages
+ /// [Read Message History]: permission/constant.READ_MESSAGE_HISTORY.html
+ #[inline]
+ pub fn get_messages<F>(&self, f: F) -> Result<Vec<Message>>
+ where F: FnOnce(GetMessages) -> GetMessages {
+ self.id.get_messages(f)
+ }
+
+ /// Gets the list of [`User`]s who have reacted to a [`Message`] with a
+ /// certain [`Emoji`].
+ ///
+ /// Refer to [`Channel::get_reaction_users`] for more information.
+ ///
+ /// **Note**: Requires the [Read Message History] permission.
+ ///
+ /// [`Channel::get_reaction_users`]: enum.Channel.html#variant.get_reaction_users
+ /// [`Emoji`]: struct.Emoji.html
+ /// [`Message`]: struct.Message.html
+ /// [`User`]: struct.User.html
+ /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
+ #[inline]
+ pub fn get_reaction_users<M, R, U>(&self,
+ message_id: M,
+ reaction_type: R,
+ limit: Option<u8>,
+ after: Option<U>)
+ -> Result<Vec<User>> where M: Into<MessageId>, R: Into<ReactionType>, U: Into<UserId> {
+ self.id.get_reaction_users(message_id, reaction_type, limit, after)
+ }
- rest::delete_messages(self.id.0, map)
+ /// Pins a [`Message`] to the channel.
+ #[inline]
+ pub fn pin<M: Into<MessageId>>(&self, message_id: M) -> Result<()> {
+ self.id.pin(message_id)
}
/// Retrieves the list of messages that have been pinned in the private
/// channel.
- #[cfg(feature="methods")]
+ #[inline]
pub fn pins(&self) -> Result<Vec<Message>> {
- rest::get_pins(self.id.0)
+ self.id.pins()
}
/// Performs a search request to the API for the channel's [`Message`]s.
@@ -830,7 +1736,6 @@ impl PrivateChannel {
/// [`ClientError::InvalidOperationAsBot`]: ../client/enum.ClientError.html#variant.InvalidOperationAsBot
/// [`Message`]: struct.Message.html
/// [`Search`]: ../utils/builder/struct.Search.html
- #[cfg(feature="methods")]
pub fn search<F>(&self, f: F) -> Result<SearchResult>
where F: FnOnce(Search) -> Search {
#[cfg(feature="cache")]
@@ -840,7 +1745,7 @@ impl PrivateChannel {
}
}
- rest::search_channel_messages(self.id.0, f(Search::default()).0)
+ self.id.search(f)
}
/// Sends a message to the channel with the given content.
@@ -854,7 +1759,6 @@ impl PrivateChannel {
/// over the limit.
///
/// [`ClientError::MessageTooLong`]: ../client/enum.ClientError.html#variant.MessageTooLong
- #[cfg(feature="methods")]
pub fn send_message(&self, content: &str) -> Result<Message> {
if let Some(length_over) = Message::overflow_length(content) {
return Err(Error::Client(ClientError::MessageTooLong(length_over)));
@@ -868,6 +1772,17 @@ impl PrivateChannel {
rest::send_message(self.id.0, map)
}
+
+ /// Unpins a [`Message`] in the channel given by its Id.
+ ///
+ /// Requires the [Manage Messages] permission.
+ ///
+ /// [`Message`]: struct.Message.html
+ /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
+ #[inline]
+ pub fn unpin<M: Into<MessageId>>(&self, message_id: M) -> Result<()> {
+ self.id.unpin(message_id.into().0)
+ }
}
impl fmt::Display for PrivateChannel {
@@ -878,6 +1793,31 @@ impl fmt::Display for PrivateChannel {
}
impl GuildChannel {
+ /// Marks the channel as being read up to a certain [`Message`].
+ ///
+ /// Refer to the documentation for [`rest::ack_message`] for more
+ /// information.
+ ///
+ /// # Errors
+ ///
+ /// If the `cache` is enabled, returns a
+ /// [`ClientError::InvalidOperationAsBot`] if the current user is a bot
+ /// user.
+ ///
+ /// [`ClientError::InvalidOperationAsBot`]: ../client/enum.ClientError.html#variant.InvalidOperationAsUser
+ /// [`Message`]: struct.Message.html
+ /// [`rest::ack_message`]: rest/fn.ack_message.html
+ pub fn ack<M: Into<MessageId>>(&self, message_id: M) -> Result<()> {
+ #[cfg(feature="cache")]
+ {
+ if CACHE.read().unwrap().user.bot {
+ return Err(Error::Client(ClientError::InvalidOperationAsBot));
+ }
+ }
+
+ rest::ack_message(self.id.0, message_id.into().0)
+ }
+
/// Broadcasts to the channel that the current user is typing.
///
/// For bots, this is a good indicator for long-running commands.
@@ -892,7 +1832,6 @@ impl GuildChannel {
///
/// [`ClientError::InvalidPermissions`]: ../client/enum.ClientError.html#variant.InvalidPermissions
/// [Send Messages]: permissions/constants.SEND_MESSAGES.html
- #[cfg(feature="methods")]
pub fn broadcast_typing(&self) -> Result<()> {
rest::broadcast_typing(self.id.0)
}
@@ -907,7 +1846,6 @@ impl GuildChannel {
/// let invite = channel.create_invite(|i| i
/// .max_uses(5));
/// ```
- #[cfg(feature="methods")]
pub fn create_invite<F>(&self, f: F) -> Result<RichInvite>
where F: FnOnce(CreateInvite) -> CreateInvite {
#[cfg(feature="cache")]
@@ -924,6 +1862,78 @@ impl GuildChannel {
rest::create_invite(self.id.0, map)
}
+ /// Creates a [permission overwrite][`PermissionOverwrite`] for either a
+ /// single [`Member`] or [`Role`] within a [`Channel`].
+ ///
+ /// Refer to the documentation for [`PermissionOverwrite`]s for more
+ /// information.
+ ///
+ /// Requires the [Manage Channels] permission.
+ ///
+ /// # Examples
+ ///
+ /// Creating a permission overwrite for a member by specifying the
+ /// [`PermissionOverwrite::Member`] variant, allowing it the [Send Messages]
+ /// permission, but denying the [Send TTS Messages] and [Attach Files]
+ /// permissions:
+ ///
+ /// ```rust,ignore
+ /// use serenity::model::{ChannelId, PermissionOverwrite, permissions};
+ ///
+ /// // assuming you are in a context
+ ///
+ /// let channel_id = 7;
+ /// let user_id = 8;
+ ///
+ /// let allow = permissions::SEND_MESSAGES;
+ /// let deny = permissions::SEND_TTS_MESSAGES | permissions::ATTACH_FILES;
+ /// let overwrite = PermissionOverwrite {
+ /// allow: allow,
+ /// deny: deny,
+ /// kind: PermissionOverwriteType::Member(user_id),
+ /// };
+ ///
+ /// let _result = context.create_permission(channel_id, overwrite);
+ /// ```
+ ///
+ /// Creating a permission overwrite for a role by specifying the
+ /// [`PermissionOverwrite::Role`] variant, allowing it the [Manage Webhooks]
+ /// permission, but denying the [Send TTS Messages] and [Attach Files]
+ /// permissions:
+ ///
+ /// ```rust,ignore
+ /// use serenity::model::{ChannelId, PermissionOverwrite, permissions};
+ ///
+ /// // assuming you are in a context
+ ///
+ /// let channel_id = 7;
+ /// let user_id = 8;
+ ///
+ /// let allow = permissions::SEND_MESSAGES;
+ /// let deny = permissions::SEND_TTS_MESSAGES | permissions::ATTACH_FILES;
+ /// let overwrite = PermissionOverwrite {
+ /// allow: allow,
+ /// deny: deny,
+ /// kind: PermissionOverwriteType::Member(user_id),
+ /// };
+ ///
+ /// let _result = context.create_permission(channel_id, overwrite);
+ /// ```
+ ///
+ /// [`Channel`]: enum.Channel.html
+ /// [`Member`]: struct.Member.html
+ /// [`PermissionOverwrite`]: struct.PermissionOverWrite.html
+ /// [`PermissionOverwrite::Member`]: struct.PermissionOverwrite.html#variant.Member
+ /// [`Role`]: struct.Role.html
+ /// [Attach Files]: permissions/constant.ATTACH_FILES.html
+ /// [Manage Channels]: permissions/constant.MANAGE_CHANNELS.html
+ /// [Manage Webhooks]: permissions/constant.MANAGE_WEBHOOKS.html
+ /// [Send TTS Messages]: permissions/constant.SEND_TTS_MESSAGES.html
+ #[inline]
+ pub fn create_permission(&self, target: PermissionOverwrite) -> Result<()> {
+ self.id.create_permission(target)
+ }
+
#[doc(hidden)]
pub fn decode(value: Value) -> Result<GuildChannel> {
let mut map = into_map(value)?;
@@ -953,7 +1963,6 @@ impl GuildChannel {
}
/// Deletes this channel, returning the channel on a successful deletion.
- #[cfg(feature="methods")]
pub fn delete(&self) -> Result<Channel> {
#[cfg(feature="cache")]
{
@@ -964,7 +1973,50 @@ impl GuildChannel {
}
}
- rest::delete_channel(self.id.0)
+ self.id.delete()
+ }
+
+ /// Deletes all messages by Ids from the given vector in the channel.
+ ///
+ /// Refer to [`Channel::delete_messages`] for more information.
+ ///
+ /// Requires the [Manage Messages] permission.
+ ///
+ /// **Note**: This uses bulk delete endpoint which is not available
+ /// for user accounts.
+ ///
+ /// **Note**: Messages that are older than 2 weeks can't be deleted using
+ /// this method.
+ ///
+ /// [`Channel::delete_messages`]: enum.Channel.html#method.delete_messages
+ /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
+ #[inline]
+ pub fn delete_messages(&self, message_ids: &[MessageId]) -> Result<()> {
+ self.id.delete_messages(message_ids)
+ }
+
+ /// Deletes all permission overrides in the channel from a member
+ /// or role.
+ ///
+ /// **Note**: Requires the [Manage Channel] permission.
+ ///
+ /// [Manage Channel]: permissions/constant.MANAGE_CHANNELS.html
+ #[inline]
+ pub fn delete_permission(&self, permission_type: PermissionOverwriteType) -> Result<()> {
+ self.id.delete_permission(permission_type)
+ }
+
+ /// Deletes the given [`Reaction`] from the channel.
+ ///
+ /// **Note**: Requires the [Manage Messages] permission, _if_ the current
+ /// user did not perform the reaction.
+ ///
+ /// [`Reaction`]: struct.Reaction.html
+ /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
+ #[inline]
+ pub fn delete_reaction<M, R>(&self, message_id: M, user_id: Option<UserId>, reaction_type: R)
+ -> Result<()> where M: Into<MessageId>, R: Into<ReactionType> {
+ self.id.delete_reaction(message_id, user_id, reaction_type)
}
/// Modifies a channel's settings, such as its position or name.
@@ -980,7 +2032,6 @@ impl GuildChannel {
/// .name("test")
/// .bitrate(86400));
/// ```
- #[cfg(feature="methods")]
pub fn edit<F>(&mut self, f: F) -> Result<()>
where F: FnOnce(EditChannel) -> EditChannel {
@@ -1010,19 +2061,79 @@ impl GuildChannel {
}
}
+ /// Gets all of the channel's invites.
+ ///
+ /// Requires the [Manage Channels] permission.
+ /// [Manage Channels]: permissions/constant.MANAGE_CHANNELS.html
+ #[inline]
+ pub fn get_invites(&self) -> Result<Vec<RichInvite>> {
+ self.id.get_invites()
+ }
+
+ /// Gets a message from the channel.
+ ///
+ /// Requires the [Read Message History] permission.
+ ///
+ /// [Read Message History]: permission/constant.READ_MESSAGE_HISTORY.html
+ #[inline]
+ pub fn get_message<M: Into<MessageId>>(&self, message_id: M) -> Result<Message> {
+ self.id.get_message(message_id)
+ }
+
+ /// Gets messages from the channel.
+ ///
+ /// Refer to [`Channel::get_messages`] for more information.
+ ///
+ /// Requires the [Read Message History] permission.
+ ///
+ /// [`Channel::get_messages`]: enum.Channel.html#method.get_messages
+ /// [Read Message History]: permission/constant.READ_MESSAGE_HISTORY.html
+ #[inline]
+ pub fn get_messages<F>(&self, f: F) -> Result<Vec<Message>>
+ where F: FnOnce(GetMessages) -> GetMessages {
+ self.id.get_messages(f)
+ }
+
+ /// Gets the list of [`User`]s who have reacted to a [`Message`] with a
+ /// certain [`Emoji`].
+ ///
+ /// Refer to [`Channel::get_reaction_users`] for more information.
+ ///
+ /// **Note**: Requires the [Read Message History] permission.
+ ///
+ /// [`Channel::get_reaction_users`]: enum.Channel.html#variant.get_reaction_users
+ /// [`Emoji`]: struct.Emoji.html
+ /// [`Message`]: struct.Message.html
+ /// [`User`]: struct.User.html
+ /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
+ pub fn get_reaction_users<M, R, U>(&self,
+ message_id: M,
+ reaction_type: R,
+ limit: Option<u8>,
+ after: Option<U>)
+ -> Result<Vec<User>> where M: Into<MessageId>, R: Into<ReactionType>, U: Into<UserId> {
+ self.id.get_reaction_users(message_id, reaction_type, limit, after)
+ }
+
/// Attempts to find this channel's guild in the Cache.
///
/// **Note**: Right now this performs a clone of the guild. This will be
/// optimized in the future.
- #[cfg(all(feature="cache", feature="methods"))]
+ #[cfg(feature="cache")]
pub fn guild(&self) -> Option<Guild> {
CACHE.read().unwrap().get_guild(self.guild_id).cloned()
}
+ /// Pins a [`Message`] to the channel.
+ #[inline]
+ pub fn pin<M: Into<MessageId>>(&self, message_id: M) -> Result<()> {
+ self.id.pin(message_id)
+ }
+
/// Gets all channel's pins.
- #[cfg(feature="methods")]
+ #[inline]
pub fn pins(&self) -> Result<Vec<Message>> {
- rest::get_pins(self.id.0)
+ self.id.pins()
}
/// Performs a search request for the channel's [`Message`]s.
@@ -1040,7 +2151,6 @@ impl GuildChannel {
/// [`ClientError::InvalidOperationAsBot`]: ../client/enum.ClientError.html#variant.InvalidOperationAsBot
/// [`Message`]: struct.Message.html
/// [`Search`]: ../utils/builder/struct.Search.html
- #[cfg(feature="methods")]
pub fn search<F>(&self, f: F) -> Result<SearchResult>
where F: FnOnce(Search) -> Search {
#[cfg(feature="cache")]
@@ -1072,7 +2182,6 @@ impl GuildChannel {
/// [`ClientError::MessageTooLong`]: ../client/enum.ClientError.html#variant.MessageTooLong
/// [`Message`]: struct.Message.html
/// [Send Messages]: permissions/constant.SEND_MESSAGES.html
- #[cfg(feature="methods")]
pub fn send_message(&self, content: &str) -> Result<Message> {
if let Some(length_over) = Message::overflow_length(content) {
return Err(Error::Client(ClientError::MessageTooLong(length_over)));
@@ -1096,12 +2205,22 @@ impl GuildChannel {
rest::send_message(self.id.0, map)
}
+ /// Unpins a [`Message`] in the channel given by its Id.
+ ///
+ /// Requires the [Manage Messages] permission.
+ ///
+ /// [`Message`]: struct.Message.html
+ /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
+ #[inline]
+ pub fn unpin<M: Into<MessageId>>(&self, message_id: M) -> Result<()> {
+ self.id.unpin(message_id.into().0)
+ }
+
/// Retrieves the channel's webhooks.
///
/// **Note**: Requires the [Manage Webhooks] permission.
///
/// [Manage Webhooks]: permissions/constant.MANAGE_WEBHOOKS.html
- #[cfg(feature="methods")]
#[inline]
pub fn webhooks(&self) -> Result<Vec<Webhook>> {
rest::get_channel_webhooks(self.id.0)
@@ -1131,7 +2250,6 @@ impl Reaction {
/// [`ClientError::InvalidPermissions`]: ../client/enum.ClientError.html#variant.InvalidPermissions
/// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
/// [permissions]: permissions
- #[cfg(feature="methods")]
pub fn delete(&self) -> Result<()> {
let user_id = feature_cache! {{
let user = if self.user_id == CACHE.read().unwrap().user.id {
@@ -1188,7 +2306,6 @@ impl Reaction {
/// [`User`]: struct.User.html
/// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
/// [permissions]: permissions
- #[cfg(feature="methods")]
pub fn users<R, U>(&self,
reaction_type: R,
limit: Option<u8>,
diff --git a/src/model/gateway.rs b/src/model/gateway.rs
index 769045c..9758e4b 100644
--- a/src/model/gateway.rs
+++ b/src/model/gateway.rs
@@ -26,7 +26,6 @@ impl Game {
/// Creates a `Game` struct that appears as a `Playing <name>` status.
///
/// **Note**: Maximum `name` length is 128.
- #[cfg(feature="methods")]
pub fn playing(name: &str) -> Game {
Game {
kind: GameType::Playing,
@@ -38,7 +37,6 @@ impl Game {
/// Creates a `Game` struct that appears as a `Streaming <name>` status.
///
/// **Note**: Maximum `name` length is 128.
- #[cfg(feature="methods")]
pub fn streaming(name: &str, url: &str) -> Game {
Game {
kind: GameType::Streaming,
diff --git a/src/model/guild.rs b/src/model/guild.rs
index fa8df32..9af9e00 100644
--- a/src/model/guild.rs
+++ b/src/model/guild.rs
@@ -1,3 +1,4 @@
+use serde_json::builder::ObjectBuilder;
use std::cmp::Ordering;
use std::collections::HashMap;
use std::fmt;
@@ -13,23 +14,17 @@ use super::utils::{
remove,
};
use super::*;
+use ::client::rest;
use ::internal::prelude::*;
+use ::utils::builder::{EditGuild, EditMember, EditRole, Search};
use ::utils::decode_array;
-#[cfg(feature="methods")]
-use serde_json::builder::ObjectBuilder;
-#[cfg(all(feature="cache", feature = "methods"))]
+#[cfg(feature="cache")]
use std::mem;
-#[cfg(all(feature="cache", feature="methods"))]
-use ::utils::builder::EditMember;
-#[cfg(feature="methods")]
-use ::utils::builder::{EditGuild, EditRole, Search};
-#[cfg(feature = "methods")]
-use ::client::rest;
-#[cfg(all(feature="cache", feature="methods"))]
+#[cfg(feature="cache")]
use ::client::CACHE;
-#[cfg(all(feature="cache", feature="methods"))]
+#[cfg(feature="cache")]
use ::utils::Colour;
impl From<PartialGuild> for GuildContainer {
@@ -58,7 +53,7 @@ impl Emoji {
/// **Note**: Only user accounts may use this method.
///
/// [Manage Emojis]: permissions/constant.MANAGE_EMOJIS.html
- #[cfg(all(feature="cache", feature="methods"))]
+ #[cfg(feature="cache")]
pub fn delete(&self) -> Result<()> {
match self.find_guild_id() {
Some(guild_id) => rest::delete_emoji(guild_id.0, self.id.0),
@@ -73,7 +68,7 @@ impl Emoji {
/// **Note**: Only user accounts may use this method.
///
/// [Manage Emojis]: permissions/constant.MANAGE_EMOJIS.html
- #[cfg(all(feature="cache", feature="methods"))]
+ #[cfg(feature="cache")]
pub fn edit(&mut self, name: &str) -> Result<()> {
match self.find_guild_id() {
Some(guild_id) => {
@@ -97,7 +92,7 @@ impl Emoji {
/// Finds the [`Guild`] that owns the emoji by looking through the Cache.
///
/// [`Guild`]: struct.Guild.html
- #[cfg(all(feature="cache", feature="methods"))]
+ #[cfg(feature="cache")]
pub fn find_guild_id(&self) -> Option<GuildId> {
CACHE.read()
.unwrap()
@@ -108,7 +103,6 @@ impl Emoji {
}
/// Generates a URL to the emoji's image.
- #[cfg(feature="methods")]
#[inline]
pub fn url(&self) -> String {
format!(cdn!("/emojis/{}.png"), self.id)
@@ -129,141 +123,37 @@ impl fmt::Display for Emoji {
}
}
-impl GuildInfo {
- /// Returns the formatted URL of the guild's icon, if the guild has an icon.
- pub fn icon_url(&self) -> Option<String> {
- self.icon.as_ref().map(|icon|
- format!(cdn!("/icons/{}/{}.webp"), self.id, icon))
+impl fmt::Display for EmojiId {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(&self.0, f)
}
}
-impl InviteGuild {
- /// Returns the formatted URL of the guild's splash image, if one exists.
- #[cfg(feature="methods")]
- pub fn splash_url(&self) -> Option<String> {
- self.icon.as_ref().map(|icon|
- format!(cdn!("/splashes/{}/{}.webp"), self.id, icon))
+impl From<Emoji> for EmojiId {
+ /// Gets the Id of an `Emoji`.
+ fn from(emoji: Emoji) -> EmojiId {
+ emoji.id
}
}
-impl PartialGuild {
- /// Edits the current user's nickname for the guild.
- ///
- /// Pass `None` to reset the nickname.
- ///
- /// **Note**: Requires the [Change Nickname] permission.
- ///
- /// [Change Nickname]: permissions/constant.CHANGE_NICKNAME.html
- #[cfg(feature="methods")]
- #[inline]
- pub fn edit_nickname(&self, new_nickname: Option<&str>) -> Result<()> {
- rest::edit_nickname(self.id.0, new_nickname)
- }
-
- /// Returns a formatted URL of the guild's icon, if the guild has an icon.
+impl GuildInfo {
+ /// Returns the formatted URL of the guild's icon, if the guild has an icon.
pub fn icon_url(&self) -> Option<String> {
self.icon.as_ref().map(|icon|
format!(cdn!("/icons/{}/{}.webp"), self.id, icon))
}
+}
- /// Performs a search request to the API for the guild's [`Message`]s.
- ///
- /// This will search all of the guild's [`Channel`]s at once, that you have
- /// the [Read Message History] permission to. Use [`search_channels`] to
- /// specify a list of [channel][`GuildChannel`]s to search, where all other
- /// channels will be excluded.
- ///
- /// Refer to the documentation for the [`Search`] builder for examples and
- /// more information.
- ///
- /// **Note**: Bot users can not search.
- ///
- /// # Errors
- ///
- /// If the `cache` is enabled, returns a
- /// [`ClientError::InvalidOperationAsBot`] if the current user is a bot.
- ///
- /// [`ClientError::InvalidOperationAsBot`]: ../client/enum.ClientError.html#variant.InvalidOperationAsBot
- /// [`Channel`]: enum.Channel.html
- /// [`GuildChannel`]: struct.GuildChannel.html
- /// [`Message`]: struct.Message.html
- /// [`Search`]: ../utils/builder/struct.Search.html
- /// [`search_channels`]: #method.search_channels
- /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
- #[cfg(feature="methods")]
- pub fn search<F>(&self, f: F) -> Result<SearchResult>
- where F: FnOnce(Search) -> Search {
- #[cfg(feature="cache")]
- {
- if CACHE.read().unwrap().user.bot {
- return Err(Error::Client(ClientError::InvalidOperationAsBot));
- }
- }
-
- rest::search_guild_messages(self.id.0, &[], f(Search::default()).0)
- }
-
- /// Performs a search request to the API for the guild's [`Message`]s in
- /// given channels.
- ///
- /// This will search all of the messages in the guild's provided
- /// [`Channel`]s by Id that you have the [Read Message History] permission
- /// to. Use [`search`] to search all of a guild's [channel][`GuildChannel`]s
- /// at once.
- ///
- /// Refer to the documentation for the [`Search`] builder for examples and
- /// more information.
- ///
- /// **Note**: Bot users can not search.
- ///
- /// # Errors
- ///
- /// If the `cache` is enabled, returns a
- /// [`ClientError::InvalidOperationAsBot`] if the current user is a bot.
- ///
- /// [`ClientError::InvalidOperationAsBot`]: ../client/enum.ClientError.html#variant.InvalidOperationAsBot
- /// [`Channel`]: enum.Channel.html
- /// [`GuildChannel`]: struct.GuildChannel.html
- /// [`Message`]: struct.Message.html
- /// [`Search`]: ../utils/builder/struct.Search.html
- /// [`search`]: #method.search
- /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
- #[cfg(feature="methods")]
- pub fn search_channels<F>(&self, channel_ids: &[ChannelId], f: F)
- -> Result<SearchResult> where F: FnOnce(Search) -> Search {
- #[cfg(feature="cache")]
- {
- if CACHE.read().unwrap().user.bot {
- return Err(Error::Client(ClientError::InvalidOperationAsBot));
- }
- }
-
- let ids = channel_ids.iter().map(|x| x.0).collect::<Vec<u64>>();
-
- rest::search_guild_messages(self.id.0, &ids, f(Search::default()).0)
- }
-
+impl InviteGuild {
/// Returns the formatted URL of the guild's splash image, if one exists.
- #[cfg(feature="methods")]
pub fn splash_url(&self) -> Option<String> {
self.icon.as_ref().map(|icon|
format!(cdn!("/splashes/{}/{}.webp"), self.id, icon))
}
-
- /// Retrieves the guild's webhooks.
- ///
- /// **Note**: Requires the [Manage Webhooks] permission.
- ///
- /// [Manage Webhooks]: permissions/constant.MANAGE_WEBHOOKS.html
- #[cfg(feature="methods")]
- #[inline]
- pub fn webhooks(&self) -> Result<Vec<Webhook>> {
- rest::get_guild_webhooks(self.id.0)
- }
}
impl Guild {
- #[cfg(all(feature="cache", feature="methods"))]
+ #[cfg(feature="cache")]
fn has_perms(&self, mut permissions: Permissions) -> Result<bool> {
let member = match self.members.get(&CACHE.read().unwrap().user.id) {
Some(member) => member,
@@ -277,8 +167,9 @@ impl Guild {
}
/// 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`.
+ /// 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.
///
@@ -301,9 +192,9 @@ impl Guild {
///
/// [`ClientError::DeleteMessageDaysAmount`]: ../client/enum.ClientError.html#variant.DeleteMessageDaysAmount
/// [`ClientError::InvalidPermissions`]: ../client/enum.ClientError.html#variant.InvalidPermissions
+ /// [`Guild::ban`]: struct.Guild.html#method.ban
/// [`User`]: struct.User.html
/// [Ban Members]: permissions/constant.BAN_MEMBERS.html
- #[cfg(feature="methods")]
pub fn ban<U: Into<UserId>>(&self, user: U, delete_message_days: u8)
-> Result<()> {
if delete_message_days > 7 {
@@ -319,7 +210,7 @@ impl Guild {
}
}
- rest::ban_user(self.id.0, user.into().0, delete_message_days)
+ self.id.ban(user.into(), delete_message_days)
}
/// Retrieves a list of [`Ban`]s for the guild.
@@ -334,7 +225,6 @@ impl Guild {
/// [`Ban`]: struct.Ban.html
/// [`ClientError::InvalidPermissions`]: ../client/enum.ClientError.html#variant.InvalidPermissions
/// [Ban Members]: permissions/constant.BAN_MEMBERS.html
- #[cfg(feature="methods")]
pub fn bans(&self) -> Result<Vec<Ban>> {
#[cfg(feature="cache")]
{
@@ -345,7 +235,43 @@ impl Guild {
}
}
- rest::get_bans(self.id.0)
+ self.id.get_bans()
+ }
+
+ /// Creates a guild with the data provided.
+ ///
+ /// Only a [`PartialGuild`] will be immediately returned, and a full
+ /// [`Guild`] will be received over a [`Shard`].
+ ///
+ /// **Note**: This endpoint is usually only available for user accounts.
+ /// Refer to Discord's information for the endpoint [here][whitelist] for
+ /// more information. If you require this as a bot, re-think what you are
+ /// doing and if it _really_ needs to be doing this.
+ ///
+ /// # Examples
+ ///
+ /// Create a guild called `"test"` in the [US West region] with no icon:
+ ///
+ /// ```rust,ignore
+ /// use serenity::model::{Guild, Region};
+ ///
+ /// let _guild = Guild::create_guild("test", Region::UsWest, None);
+ /// ```
+ ///
+ /// [`Guild`]: struct.Guild.html
+ /// [`PartialGuild`]: struct.PartialGuild.html
+ /// [`Shard`]: ../gateway/struct.Shard.html
+ /// [US West region]: enum.Region.html#variant.UsWest
+ /// [whitelist]: https://discordapp.com/developers/docs/resources/guild#create-guild
+ pub fn create(name: &str, region: Region, icon: Option<&str>)
+ -> Result<PartialGuild> {
+ let map = ObjectBuilder::new()
+ .insert("icon", icon)
+ .insert("name", name)
+ .insert("region", region.name())
+ .build();
+
+ rest::create_guild(map)
}
/// Creates a new [`Channel`] in the guild.
@@ -370,7 +296,6 @@ impl Guild {
/// [`Channel`]: struct.Channel.html
/// [`ClientError::InvalidPermissions`]: ../client/enum.ClientError.html#variant.InvalidPermissions
/// [Manage Channels]: permissions/constants.MANAGE_CHANNELS.html
- #[cfg(feature="methods")]
pub fn create_channel(&mut self, name: &str, kind: ChannelType)
-> Result<Channel> {
#[cfg(feature="cache")]
@@ -382,20 +307,58 @@ impl Guild {
}
}
- let map = ObjectBuilder::new()
- .insert("name", name)
- .insert("type", kind.name())
- .build();
+ self.id.create_channel(name, kind)
+ }
- rest::create_channel(self.id.0, map)
+ /// 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`]: ../utils/builder/struct.EditProfile.html#method.avatar
+ /// [`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) -> Result<Emoji> {
+ self.id.create_emoji(name, image)
}
- /// Creates a new [`Role`] in the guild with the data set, if any.
+ /// Creates an integration for the guild.
+ ///
+ /// Requires the [Manage Guild] permission.
///
- /// See the documentation for [`Context::create_role`] on how to use this.
+ /// [Manage Guild]: permissions/constant.MANAGE_GUILD.html
+ #[inline]
+ pub fn create_integration<I>(&self, integration_id: I, kind: &str) -> Result<()>
+ where I: Into<IntegrationId> {
+ self.id.create_integration(integration_id, 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
+ /// let role = context.create_role(guild_id, |r| r
+ /// .hoist(true)
+ /// .name("role"));
+ /// ```
+ ///
/// # Errors
///
/// If the `cache` is enabled, returns a [`ClientError::InvalidPermissions`]
@@ -405,7 +368,6 @@ impl Guild {
/// [`Context::create_role`]: ../client/struct.Context.html#method.create_role
/// [`Role`]: struct.Role.html
/// [Manage Roles]: permissions/constants.MANAGE_ROLES.html
- #[cfg(feature="methods")]
pub fn create_role<F>(&self, f: F) -> Result<Role>
where F: FnOnce(EditRole) -> EditRole {
#[cfg(feature="cache")]
@@ -417,7 +379,7 @@ impl Guild {
}
}
- rest::create_role(self.id.0, f(EditRole::default()).0.build())
+ self.id.create_role(f)
}
#[doc(hidden)]
@@ -464,8 +426,7 @@ impl Guild {
})
}
-
- /// Deletes the current guild if the current account is the owner of the
+ /// 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.
@@ -476,7 +437,6 @@ impl Guild {
/// if the current user is not the guild owner.
///
/// [`ClientError::InvalidUser`]: ../client/enum.ClientError.html#variant.InvalidUser
- #[cfg(feature="methods")]
pub fn delete(&self) -> Result<PartialGuild> {
#[cfg(feature="cache")]
{
@@ -487,15 +447,68 @@ impl Guild {
}
}
- rest::delete_guild(self.id.0)
+ self.id.delete()
+ }
+
+ /// 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) -> Result<()> {
+ self.id.delete_emoji(emoji_id)
+ }
+
+ /// 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) -> Result<()> {
+ self.id.delete_integration(integration_id)
+ }
+
+ /// 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) -> Result<()> {
+ self.id.delete_role(role_id)
}
- /// Edits the current guild with new data where specified. See the
- /// documentation for [`Context::edit_guild`] on how to use this.
+ /// Edits the current guild with new data where specified.
+ ///
+ /// Refer to `EditGuild`'s documentation for a full list of methods.
+ ///
+ /// Also see [`Guild::edit`] if you have the `methods` feature enabled.
///
/// **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 [`ClientError::InvalidPermissions`]
@@ -504,7 +517,6 @@ impl Guild {
/// [`ClientError::InvalidPermissions`]: ../client/enum.ClientError.html#variant.InvalidPermissions
/// [`Context::edit_guild`]: ../client/struct.Context.html#method.edit_guild
/// [Manage Guild]: permissions/constants.MANAGE_GUILD.html
- #[cfg(feature="methods")]
pub fn edit<F>(&mut self, f: F) -> Result<()>
where F: FnOnce(EditGuild) -> EditGuild {
#[cfg(feature="cache")]
@@ -516,9 +528,7 @@ impl Guild {
}
}
- let map = f(EditGuild::default()).0.build();
-
- match rest::edit_guild(self.id.0, map) {
+ match self.id.edit(f) {
Ok(guild) => {
self.afk_channel_id = guild.afk_channel_id;
self.afk_timeout = guild.afk_timeout;
@@ -540,6 +550,42 @@ impl Guild {
}
}
+ /// 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) -> Result<Emoji> {
+ self.id.edit_emoji(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) -> Result<()>
+ where F: FnOnce(EditMember) -> EditMember, U: Into<UserId> {
+ self.id.edit_member(user_id, f)
+ }
+
/// Edits the current user's nickname for the guild.
///
/// Pass `None` to reset the nickname.
@@ -554,7 +600,6 @@ impl Guild {
///
/// [`ClientError::InvalidPermissions`]: ../client/enum.ClientError.html#variant.InvalidPermissions
/// [Change Nickname]: permissions/constant.CHANGE_NICKNAME.html
- #[cfg(feature="methods")]
pub fn edit_nickname(&self, new_nickname: Option<&str>) -> Result<()> {
#[cfg(feature="cache")]
{
@@ -565,7 +610,78 @@ impl Guild {
}
}
- rest::edit_nickname(self.id.0, new_nickname)
+ self.id.edit_nickname(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) -> Result<Role>
+ where F: FnOnce(EditRole) -> EditRole, R: Into<RoleId> {
+ self.id.edit_role(role_id, f)
+ }
+
+ /// Gets a partial amount of guild data by its Id.
+ ///
+ /// Requires that the current user be in the guild.
+ #[inline]
+ pub fn get<G: Into<GuildId>>(guild_id: G) -> Result<PartialGuild> {
+ guild_id.into().get()
+ }
+
+ /// Gets a list of the guild's bans.
+ ///
+ /// Requires the [Ban Members] permission.
+ #[inline]
+ pub fn get_bans(&self) -> Result<Vec<Ban>> {
+ self.id.get_bans()
+ }
+
+ /// Gets all of the guild's channels over the REST API.
+ ///
+ /// [`Guild`]: struct.Guild.html
+ #[inline]
+ pub fn get_channels(&self) -> Result<HashMap<ChannelId, GuildChannel>> {
+ self.id.get_channels()
+ }
+
+ /// Gets an emoji in the guild by Id.
+ ///
+ /// Requires the [Manage Emojis] permission.
+ ///
+ /// [Manage Emojis]: permissions/constant.MANAGE_EMOJIS.html
+ #[inline]
+ pub fn get_emoji<E: Into<EmojiId>>(&self, emoji_id: E) -> Result<Emoji> {
+ self.id.get_emoji(emoji_id)
+ }
+
+ /// Gets a list of all of the guild's emojis.
+ ///
+ /// Requires the [Manage Emojis] permission.
+ ///
+ /// [Manage Emojis]: permissions/constant.MANAGE_EMOJIS.html
+ #[inline]
+ pub fn get_emojis(&self) -> Result<Vec<Emoji>> {
+ self.id.get_emojis()
+ }
+
+ /// Gets all integration of the guild.
+ ///
+ /// This performs a request over the REST API.
+ #[inline]
+ pub fn get_integrations(&self) -> Result<Vec<Integration>> {
+ self.id.get_integrations()
}
/// Retrieves the active invites for the guild.
@@ -579,7 +695,6 @@ impl Guild {
///
/// [`ClientError::InvalidPermissions`]: ../client/enum.ClientError.html#variant.InvalidPermissions
/// [Manage Guild]: permissions/constant.MANAGE_GUILD.html
- #[cfg(feature="methods")]
pub fn get_invites(&self) -> Result<Vec<RichInvite>> {
#[cfg(feature="cache")]
{
@@ -590,7 +705,29 @@ impl Guild {
}
}
- rest::get_guild_invites(self.id.0)
+ self.id.get_invites()
+ }
+
+ /// Gets a user's [`Member`] for the guild by Id.
+ ///
+ /// [`Guild`]: struct.Guild.html
+ /// [`Member`]: struct.Member.html
+ #[inline]
+ pub fn get_member<U: Into<UserId>>(&self, user_id: U) -> Result<Member> {
+ self.id.get_member(user_id)
+ }
+
+ /// 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 get_members<U>(&self, limit: Option<u64>, after: Option<U>)
+ -> Result<Vec<Member>> where U: Into<UserId> {
+ self.id.get_members(limit, after)
}
/// Retrieves the first [`Member`] found that matches the name - with an
@@ -631,11 +768,40 @@ impl Guild {
};
name_matches && discrim_matches
- }).or(self.members.iter().find(|&(_member_id, member)| {
+ }).or_else(|| self.members.iter().find(|&(_member_id, member)| {
member.nick.as_ref().map_or(false, |nick| nick == name)
})).map(|(_member_id, member)| member)
}
+ /// 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 [`ClientError::InvalidPermissions`]
+ /// if the current user does not have permission to perform bans.
+ ///
+ /// [`ClientError::InvalidPermissions`]: ../client/enum.ClientError.html#variant.InvalidPermissions
+ /// [`GuildPrune`]: struct.GuildPrune.html
+ /// [`Member`]: struct.Member.html
+ /// [Kick Members]: permissions/constant.KICK_MEMBERS.html
+ pub fn get_prune_count(&self, days: u16) -> Result<GuildPrune> {
+ #[cfg(feature="cache")]
+ {
+ let req = permissions::KICK_MEMBERS;
+
+ if !self.has_perms(req)? {
+ return Err(Error::Client(ClientError::InvalidPermissions(req)));
+ }
+ }
+
+ self.id.get_prune_count(days)
+ }
+
/// Returns the formatted URL of the guild's icon, if one exists.
pub fn icon_url(&self) -> Option<String> {
self.icon.as_ref().map(|icon|
@@ -644,14 +810,37 @@ impl Guild {
/// Checks if the guild is 'large'. A guild is considered large if it has
/// more than 250 members.
+ #[inline]
pub fn is_large(&self) -> bool {
self.members.len() > 250
}
+ /// 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) -> Result<()> {
+ self.id.kick(user_id)
+ }
+
/// Leaves the guild.
- #[cfg(feature="methods")]
+ #[inline]
pub fn leave(&self) -> Result<PartialGuild> {
- rest::leave_guild(self.id.0)
+ self.id.leave()
+ }
+
+ /// 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)
+ -> Result<()> where C: Into<ChannelId>, U: Into<UserId> {
+ self.id.move_member(user_id, channel_id)
}
/// Calculate a [`User`]'s permissions in a given channel in the guild.
@@ -770,40 +959,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 [`ClientError::InvalidPermissions`]
- /// if the current user does not have permission to perform bans.
- ///
- /// [`ClientError::InvalidPermissions`]: ../client/enum.ClientError.html#variant.InvalidPermissions
- /// [`GuildPrune`]: struct.GuildPrune.html
- /// [`Member`]: struct.Member.html
- /// [Kick Members]: permissions/constant.KICK_MEMBERS.html
- #[cfg(feature="methods")]
- pub fn prune_count(&self, days: u16) -> Result<GuildPrune> {
- #[cfg(feature="cache")]
- {
- let req = permissions::KICK_MEMBERS;
-
- if !self.has_perms(req)? {
- return Err(Error::Client(ClientError::InvalidPermissions(req)));
- }
- }
-
- let map = ObjectBuilder::new()
- .insert("days", days)
- .build();
-
- rest::get_guild_prune_count(self.id.0, map)
- }
-
/// Performs a search request to the API for the guild's [`Message`]s.
///
/// This will search all of the guild's [`Channel`]s at once, that you have
@@ -828,9 +983,7 @@ impl Guild {
/// [`Search`]: ../utils/builder/struct.Search.html
/// [`search_channels`]: #method.search_channels
/// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
- #[cfg(feature="methods")]
- pub fn search<F>(&self, f: F) -> Result<SearchResult>
- where F: FnOnce(Search) -> Search {
+ pub fn search<F: FnOnce(Search) -> Search>(&self, f: F) -> Result<SearchResult> {
#[cfg(feature="cache")]
{
if CACHE.read().unwrap().user.bot {
@@ -866,7 +1019,6 @@ impl Guild {
/// [`Search`]: ../utils/builder/struct.Search.html
/// [`search`]: #method.search
/// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
- #[cfg(feature = "methods")]
pub fn search_channels<F>(&self, channel_ids: &[ChannelId], f: F)
-> Result<SearchResult> where F: FnOnce(Search) -> Search {
#[cfg(feature="cache")]
@@ -876,18 +1028,25 @@ impl Guild {
}
}
- let ids = channel_ids.iter().map(|x| x.0).collect::<Vec<u64>>();
-
- rest::search_guild_messages(self.id.0, &ids, f(Search::default()).0)
+ self.id.search_channels(channel_ids, f)
}
/// Returns the formatted URL of the guild's splash image, if one exists.
- #[cfg(feature="methods")]
pub fn splash_url(&self) -> Option<String> {
self.icon.as_ref().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: Into<IntegrationId>>(&self, integration_id: I) -> Result<()> {
+ self.id.start_integration_sync(integration_id)
+ }
+
/// Starts a prune of [`Member`]s.
///
/// See the documentation on [`GuildPrune`] for more information.
@@ -903,7 +1062,6 @@ impl Guild {
/// [`GuildPrune`]: struct.GuildPrune.html
/// [`Member`]: struct.Member.html
/// [Kick Members]: permissions/constant.KICK_MEMBERS.html
- #[cfg(feature="methods")]
pub fn start_prune(&self, days: u16) -> Result<GuildPrune> {
#[cfg(feature="cache")]
{
@@ -914,11 +1072,7 @@ impl Guild {
}
}
- let map = ObjectBuilder::new()
- .insert("days", days)
- .build();
-
- rest::start_guild_prune(self.id.0, map)
+ self.id.start_prune(days)
}
/// Unbans the given [`User`] from the guild.
@@ -933,8 +1087,7 @@ impl Guild {
/// [`ClientError::InvalidPermissions`]: ../client/enum.ClientError.html#variant.InvalidPermissions
/// [`User`]: struct.User.html
/// [Ban Members]: permissions/constant.BAN_MEMBERS.html
- #[cfg(feature="methods")]
- pub fn unban<U: Into<UserId>>(&self, user: U) -> Result<()> {
+ pub fn unban<U: Into<UserId>>(&self, user_id: U) -> Result<()> {
#[cfg(feature="cache")]
{
let req = permissions::BAN_MEMBERS;
@@ -944,7 +1097,494 @@ impl Guild {
}
}
- rest::remove_ban(self.id.0, user.into().0)
+ self.id.unban(user_id)
+ }
+
+ /// Retrieves the guild's webhooks.
+ ///
+ /// **Note**: Requires the [Manage Webhooks] permission.
+ ///
+ /// [Manage Webhooks]: permissions/constant.MANAGE_WEBHOOKS.html
+ #[inline]
+ pub fn webhooks(&self) -> Result<Vec<Webhook>> {
+ self.id.webhooks()
+ }
+}
+
+impl GuildId {
+ /// 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
+ /// use serenity::model::GuildId;
+ ///
+ /// // assuming a `user` has already been bound
+ /// let _ = GuildId(81384788765712384).ban(user, 4);
+ /// ```
+ ///
+ /// # Errors
+ ///
+ /// Returns a [`ClientError::DeleteMessageDaysAmount`] if the number of
+ /// days' worth of messages to delete is over the maximum.
+ ///
+ /// [`ClientError::DeleteMessageDaysAmount`]: ../client/enum.ClientError.html#variant.DeleteMessageDaysAmount
+ /// [`Guild::ban`]: struct.Guild.html#method.ban
+ /// [`User`]: struct.User.html
+ /// [Ban Members]: permissions/constant.BAN_MEMBERS.html
+ pub fn ban<U: Into<UserId>>(&self, user: U, delete_message_days: u8)
+ -> Result<()> {
+ if delete_message_days > 7 {
+ return Err(Error::Client(ClientError::DeleteMessageDaysAmount(delete_message_days)));
+ }
+
+ rest::ban_user(self.0, user.into().0, delete_message_days)
+ }
+
+ /// Creates a [`GuildChannel`] in the the guild.
+ ///
+ /// Refer to [`rest::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, GuildId};
+ ///
+ /// let _channel = GuildId(7).create_channel("test", ChannelType::Voice);
+ /// ```
+ ///
+ /// [`GuildChannel`]: struct.GuildChannel.html
+ /// [`rest::create_channel`]: rest/fn.create_channel.html
+ /// [Manage Channels]: permissions/constant.MANAGE_CHANNELS.html
+ pub fn create_channel(&self, name: &str, kind: ChannelType) -> Result<Channel> {
+ let map = ObjectBuilder::new()
+ .insert("name", name)
+ .insert("type", kind.name())
+ .build();
+
+ rest::create_channel(self.0, map)
+ }
+
+ /// 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`]: ../utils/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
+ pub fn create_emoji(&self, name: &str, image: &str) -> Result<Emoji> {
+ let map = ObjectBuilder::new()
+ .insert("name", name)
+ .insert("image", image)
+ .build();
+
+ rest::create_emoji(self.0, map)
+ }
+
+ /// Creates an integration for the guild.
+ ///
+ /// Requires the [Manage Guild] permission.
+ ///
+ /// [Manage Guild]: permissions/constant.MANAGE_GUILD.html
+ pub fn create_integration<I>(&self, integration_id: I, kind: &str)
+ -> Result<()> where I: Into<IntegrationId> {
+ let integration_id = integration_id.into();
+ let map = ObjectBuilder::new()
+ .insert("id", integration_id.0)
+ .insert("type", kind)
+ .build();
+
+ rest::create_guild_integration(self.0, integration_id.0, map)
+ }
+
+ /// 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.
+ ///
+ /// [`Guild::create_role`]: struct.Guild.html#method.create_role
+ /// [Manage Roles]: permissions/constants.MANAGE_ROLES.html
+ #[inline]
+ pub fn create_role<F: FnOnce(EditRole) -> EditRole>(&self, f: F) -> Result<Role> {
+ rest::create_role(self.0, f(EditRole::default()).0.build())
+ }
+
+ /// Deletes the current guild if the current account is the owner of the
+ /// guild.
+ ///
+ /// Refer to [`Guild::delete`] for more information.
+ ///
+ /// **Note**: Requires the current user to be the owner of the guild.
+ ///
+ /// [`Guild::delete`]: struct.Guild.html#method.delete
+ #[inline]
+ pub fn delete(&self) -> Result<PartialGuild> {
+ rest::delete_guild(self.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) -> Result<()> {
+ rest::delete_emoji(self.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) -> Result<()> {
+ rest::delete_guild_integration(self.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) -> Result<()> {
+ rest::delete_role(self.0, role_id.into().0)
+ }
+
+ /// Edits the current guild with new data where specified.
+ ///
+ /// Refer to [`Guild::edit`] for more information.
+ ///
+ /// **Note**: Requires the current user to have the [Manage Guild]
+ /// permission.
+ ///
+ /// [`Guild::edit`]: struct.Guild.html#method.edit
+ /// [Manage Guild]: permissions/constants.MANAGE_GUILD.html
+ #[inline]
+ pub fn edit<F: FnOnce(EditGuild) -> EditGuild>(&mut self, f: F) -> Result<PartialGuild> {
+ rest::edit_guild(self.0, f(EditGuild::default()).0.build())
+ }
+
+ /// 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
+ pub fn edit_emoji<E: Into<EmojiId>>(&self, emoji_id: E, name: &str) -> Result<Emoji> {
+ let map = ObjectBuilder::new()
+ .insert("name", name)
+ .build();
+
+ rest::edit_emoji(self.0, emoji_id.into().0, map)
+ }
+
+ /// 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) -> Result<()>
+ where F: FnOnce(EditMember) -> EditMember, U: Into<UserId> {
+ rest::edit_member(self.0, user_id.into().0, f(EditMember::default()).0.build())
+ }
+
+ /// Edits the current user's nickname for the guild.
+ ///
+ /// Pass `None` to reset the nickname.
+ ///
+ /// Requires the [Change Nickname] permission.
+ ///
+ /// [Change Nickname]: permissions/constant.CHANGE_NICKNAME.html
+ #[inline]
+ pub fn edit_nickname(&self, new_nickname: Option<&str>) -> Result<()> {
+ rest::edit_nickname(self.0, new_nickname)
+ }
+
+ /// Edits a [`Role`], optionally setting its new fields.
+ ///
+ /// Requires the [Manage Roles] permission.
+ ///
+ /// # Examples
+ ///
+ /// Make a role hoisted:
+ ///
+ /// ```rust,ignore
+ /// use serenity::model::{GuildId, RoleId};
+ ///
+ /// GuildId(7).edit_role(RoleId(8), |r| r.hoist(true));
+ /// ```
+ ///
+ /// [`Role`]: struct.Role.html
+ /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
+ #[inline]
+ pub fn edit_role<F, R>(&self, role_id: R, f: F) -> Result<Role>
+ where F: FnOnce(EditRole) -> EditRole, R: Into<RoleId> {
+ rest::edit_role(self.0, role_id.into().0, f(EditRole::default()).0.build())
+ }
+
+ /// Search the cache for the guild.
+ #[cfg(feature="cache")]
+ pub fn find(&self) -> Option<Guild> {
+ CACHE.read().unwrap().get_guild(*self).cloned()
+ }
+
+ /// Requests the guild over REST.
+ ///
+ /// Note that this will not be a complete guild, as REST does not send
+ /// all data with a guild retrieval.
+ #[inline]
+ pub fn get(&self) -> Result<PartialGuild> {
+ rest::get_guild(self.0)
+ }
+
+ /// Gets a list of the guild's bans.
+ ///
+ /// Requires the [Ban Members] permission.
+ #[inline]
+ pub fn get_bans(&self) -> Result<Vec<Ban>> {
+ rest::get_bans(self.0)
+ }
+
+ /// Gets all of the guild's channels over the REST API.
+ ///
+ /// [`Guild`]: struct.Guild.html
+ pub fn get_channels(&self) -> Result<HashMap<ChannelId, GuildChannel>> {
+ let mut channels = HashMap::new();
+
+ for channel in rest::get_channels(self.0)? {
+ channels.insert(channel.id, channel);
+ }
+
+ Ok(channels)
+ }
+
+ /// Gets an emoji in the guild by Id.
+ ///
+ /// Requires the [Manage Emojis] permission.
+ ///
+ /// [Manage Emojis]: permissions/constant.MANAGE_EMOJIS.html
+ #[inline]
+ pub fn get_emoji<E: Into<EmojiId>>(&self, emoji_id: E) -> Result<Emoji> {
+ rest::get_emoji(self.0, emoji_id.into().0)
+ }
+
+ /// Gets a list of all of the guild's emojis.
+ ///
+ /// Requires the [Manage Emojis] permission.
+ ///
+ /// [Manage Emojis]: permissions/constant.MANAGE_EMOJIS.html
+ #[inline]
+ pub fn get_emojis(&self) -> Result<Vec<Emoji>> {
+ rest::get_emojis(self.0)
+ }
+
+ /// Gets all integration of the guild.
+ ///
+ /// This performs a request over the REST API.
+ #[inline]
+ pub fn get_integrations(&self) -> Result<Vec<Integration>> {
+ rest::get_guild_integrations(self.0)
+ }
+
+ /// Gets all of the guild's invites.
+ ///
+ /// Requires the [Manage Guild] permission.
+ ///
+ /// [Manage Guild]: permissions/struct.MANAGE_GUILD.html
+ #[inline]
+ pub fn get_invites(&self) -> Result<Vec<RichInvite>> {
+ rest::get_guild_invites(self.0)
+ }
+
+ /// Gets a user's [`Member`] for the guild by Id.
+ ///
+ /// [`Guild`]: struct.Guild.html
+ /// [`Member`]: struct.Member.html
+ #[inline]
+ pub fn get_member<U: Into<UserId>>(&self, user_id: U) -> Result<Member> {
+ rest::get_member(self.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 get_members<U>(&self, limit: Option<u64>, after: Option<U>)
+ -> Result<Vec<Member>> where U: Into<UserId> {
+ rest::get_guild_members(self.0, limit, after.map(|x| x.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
+ pub fn get_prune_count(&self, days: u16) -> Result<GuildPrune> {
+ let map = ObjectBuilder::new()
+ .insert("days", days)
+ .build();
+
+ rest::get_guild_prune_count(self.0, map)
+ }
+
+ /// 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) -> Result<()> {
+ rest::kick_member(self.0, user_id.into().0)
+ }
+
+ /// Leaves the guild.
+ #[inline]
+ pub fn leave(&self) -> Result<PartialGuild> {
+ rest::leave_guild(self.0)
+ }
+
+ /// Moves a member to a specific voice channel.
+ ///
+ /// Requires the [Move Members] permission.
+ ///
+ /// [Move Members]: permissions/constant.MOVE_MEMBERS.html
+ pub fn move_member<C, U>(&self, user_id: U, channel_id: C)
+ -> Result<()> where C: Into<ChannelId>, U: Into<UserId> {
+ let map = ObjectBuilder::new()
+ .insert("channel_id", channel_id.into().0)
+ .build();
+
+ rest::edit_member(self.0, user_id.into().0, map)
+ }
+
+ /// Performs a search request to the API for the guild's [`Message`]s.
+ ///
+ /// This will search all of the guild's [`Channel`]s at once, that you have
+ /// the [Read Message History] permission to. Use [`search_channels`] to
+ /// specify a list of [channel][`GuildChannel`]s to search, where all other
+ /// channels will be excluded.
+ ///
+ /// Refer to the documentation for the [`Search`] builder for examples and
+ /// more information.
+ ///
+ /// [`Channel`]: enum.Channel.html
+ /// [`GuildChannel`]: struct.GuildChannel.html
+ /// [`Message`]: struct.Message.html
+ /// [`Search`]: ../utils/builder/struct.Search.html
+ /// [`search_channels`]: #method.search_channels
+ /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
+ #[inline]
+ pub fn search<F: FnOnce(Search) -> Search>(&self, f: F) -> Result<SearchResult> {
+ rest::search_guild_messages(self.0, &[], f(Search::default()).0)
+ }
+
+ /// Performs a search request to the API for the guild's [`Message`]s in
+ /// given channels.
+ ///
+ /// Refer to [`Guild::search_channels`] for more information.
+ ///
+ /// Refer to the documentation for the [`Search`] builder for examples and
+ /// more information.
+ ///
+ /// **Note**: Bot users can not search.
+ ///
+ /// [`Guild::search_channels`]: struct.Guild.html#method.search_channels
+ /// [`Message`]: struct.Message.html
+ pub fn search_channels<F>(&self, channel_ids: &[ChannelId], f: F)
+ -> Result<SearchResult> where F: FnOnce(Search) -> Search {
+ let ids = channel_ids.iter().map(|x| x.0).collect::<Vec<u64>>();
+
+ rest::search_guild_messages(self.0, &ids, f(Search::default()).0)
+ }
+
+ /// 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: Into<IntegrationId>>(&self, integration_id: I) -> Result<()> {
+ rest::start_integration_sync(self.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.
+ ///
+ /// [`GuildPrune`]: struct.GuildPrune.html
+ /// [`Member`]: struct.Member.html
+ /// [Kick Members]: permissions/constant.KICK_MEMBERS.html
+ pub fn start_prune(&self, days: u16) -> Result<GuildPrune> {
+ let map = ObjectBuilder::new()
+ .insert("days", days)
+ .build();
+
+ rest::start_guild_prune(self.0, map)
+ }
+
+ /// 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) -> Result<()> {
+ rest::remove_ban(self.0, user_id.into().0)
}
/// Retrieves the guild's webhooks.
@@ -952,10 +1592,50 @@ impl Guild {
/// **Note**: Requires the [Manage Webhooks] permission.
///
/// [Manage Webhooks]: permissions/constant.MANAGE_WEBHOOKS.html
- #[cfg(feature="methods")]
#[inline]
pub fn webhooks(&self) -> Result<Vec<Webhook>> {
- rest::get_guild_webhooks(self.id.0)
+ rest::get_guild_webhooks(self.0)
+ }
+}
+
+impl fmt::Display for GuildId {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(&self.0, f)
+ }
+}
+
+impl From<PartialGuild> for GuildId {
+ /// Gets the Id of a partial guild.
+ fn from(guild: PartialGuild) -> GuildId {
+ guild.id
+ }
+}
+
+impl From<GuildInfo> for GuildId {
+ /// Gets the Id of Guild information struct.
+ fn from(guild_info: GuildInfo) -> GuildId {
+ guild_info.id
+ }
+}
+
+impl From<InviteGuild> for GuildId {
+ /// Gets the Id of Invite Guild struct.
+ fn from(invite_guild: InviteGuild) -> GuildId {
+ invite_guild.id
+ }
+}
+
+impl From<Guild> for GuildId {
+ /// Gets the Id of Guild.
+ fn from(live_guild: Guild) -> GuildId {
+ live_guild.id
+ }
+}
+
+impl From<Integration> for IntegrationId {
+ /// Gets the Id of integration.
+ fn from(integration: Integration) -> IntegrationId {
+ integration.id
}
}
@@ -967,7 +1647,7 @@ impl Member {
///
/// [`Role`]: struct.Role.html
/// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
- #[cfg(all(feature="cache", feature="methods"))]
+ #[cfg(feature="cache")]
pub fn add_role<R: Into<RoleId>>(&mut self, role_id: R) -> Result<()> {
let role_id = role_id.into();
@@ -994,7 +1674,7 @@ impl Member {
///
/// [`Role`]: struct.Role.html
/// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
- #[cfg(all(feature="cache", feature="methods"))]
+ #[cfg(feature="cache")]
pub fn add_roles(&mut self, role_ids: &[RoleId]) -> Result<()> {
let guild_id = self.find_guild()?;
self.roles.extend_from_slice(role_ids);
@@ -1016,23 +1696,25 @@ impl Member {
///
/// **Note**: Requires the [Ban Members] role.
///
+ /// # Errors
+ ///
+ /// Returns a [`ClientError::GuildNotFound`] if the guild could not be
+ /// found.
+ ///
+ /// [`ClientError::GuildNotFound`]: ../client/enum.ClientError.html#variant.GuildNotFound
+ ///
/// [Ban Members]: permissions/constant.BAN_MEMBERS.html
- #[cfg(all(feature="cache", feature="methods"))]
+ #[cfg(feature="cache")]
pub fn ban(&self, delete_message_days: u8) -> Result<()> {
- let guild_id = self.find_guild()?;
-
- rest::ban_user(guild_id.0,
- self.user.id.0,
- delete_message_days)
+ rest::ban_user(self.find_guild()?.0, self.user.id.0, delete_message_days)
}
/// Determines the member's colour.
- #[cfg(all(feature="cache", feature="methods"))]
+ #[cfg(feature="cache")]
pub fn colour(&self) -> Option<Colour> {
- let default = Colour::default();
let guild_id = match self.find_guild() {
Ok(guild_id) => guild_id,
- Err(_why) => return None,
+ Err(_) => return None,
};
let cache = CACHE.read().unwrap();
@@ -1047,18 +1729,21 @@ impl Member {
.collect::<Vec<&Role>>();
roles.sort_by(|a, b| b.cmp(a));
+ let default = Colour::default();
+
roles.iter().find(|r| r.colour.0 != default.0).map(|r| r.colour)
}
/// Calculates the member's display name.
///
/// The nickname takes priority over the member's username if it exists.
+ #[inline]
pub fn display_name(&self) -> &str {
self.nick.as_ref().unwrap_or(&self.user.name)
}
/// Returns the DiscordTag of a Member, taking possible nickname into account.
- #[cfg(feature="methods")]
+ #[inline]
pub fn distinct(&self) -> String {
format!("{}#{}", self.display_name(), self.user.discriminator)
}
@@ -1071,7 +1756,7 @@ impl Member {
///
/// [`Context::edit_member`]: ../client/struct.Context.html#method.edit_member
/// [`EditMember`]: ../builder/struct.EditMember.html
- #[cfg(all(feature="cache", feature="methods"))]
+ #[cfg(feature="cache")]
pub fn edit<F>(&self, f: F) -> Result<()>
where F: FnOnce(EditMember) -> EditMember {
let guild_id = self.find_guild()?;
@@ -1082,8 +1767,14 @@ impl Member {
/// Finds the Id of the [`Guild`] that the member is in.
///
+ /// # Errors
+ ///
+ /// Returns a [`ClientError::GuildNotFound`] if the guild could not be
+ /// found.
+ ///
+ /// [`ClientError::GuildNotFound`]: ../client/enum.ClientError.html#variant.GuildNotFound
/// [`Guild`]: struct.Guild.html
- #[cfg(all(feature="cache", feature="methods"))]
+ #[cfg(feature="cache")]
pub fn find_guild(&self) -> Result<GuildId> {
CACHE.read()
.unwrap()
@@ -1110,7 +1801,7 @@ impl Member {
///
/// [`Role`]: struct.Role.html
/// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
- #[cfg(all(feature="cache", feature="methods"))]
+ #[cfg(feature="cache")]
pub fn remove_role<R: Into<RoleId>>(&mut self, role_id: R) -> Result<()> {
let role_id = role_id.into();
@@ -1136,7 +1827,7 @@ impl Member {
///
/// [`Role`]: struct.Role.html
/// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
- #[cfg(all(feature="cache", feature="methods"))]
+ #[cfg(feature="cache")]
pub fn remove_roles(&mut self, role_ids: &[RoleId]) -> Result<()> {
let guild_id = self.find_guild()?;
self.roles.retain(|r| !role_ids.contains(r));
@@ -1158,7 +1849,7 @@ impl Member {
/// This is shorthand for manually searching through the CACHE.
///
/// If role data can not be found for the member, then `None` is returned.
- #[cfg(all(feature="cache", feature="methods"))]
+ #[cfg(feature="cache")]
pub fn roles(&self) -> Option<Vec<Role>> {
CACHE.read().unwrap()
.guilds
@@ -1172,6 +1863,23 @@ impl Member {
.cloned()
.collect())
}
+
+ /// Unbans the [`User`] from the guild.
+ ///
+ /// **Note**: Requires the [Ban Members] permission.
+ ///
+ /// # Errors
+ ///
+ /// If the `cache` is enabled, returns a [`ClientError::InvalidPermissions`]
+ /// if the current user does not have permission to perform bans.
+ ///
+ /// [`ClientError::InvalidPermissions`]: ../client/enum.ClientError.html#variant.InvalidPermissions
+ /// [`User`]: struct.User.html
+ /// [Ban Members]: permissions/constant.BAN_MEMBERS.html
+ #[cfg(feature="cache")]
+ pub fn unban(&self) -> Result<()> {
+ rest::remove_ban(self.find_guild()?.0, self.user.id.0)
+ }
}
impl fmt::Display for Member {
@@ -1190,6 +1898,489 @@ impl fmt::Display for Member {
}
}
+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 [`ClientError::DeleteMessageDaysAmount`] if the number of
+ /// days' worth of messages to delete is over the maximum.
+ ///
+ /// [`ClientError::DeleteMessageDaysAmount`]: ../client/enum.ClientError.html#variant.DeleteMessageDaysAmount
+ /// [`User`]: struct.User.html
+ /// [Ban Members]: permissions/constant.BAN_MEMBERS.html
+ pub fn ban<U: Into<UserId>>(&self, user: U, delete_message_days: u8)
+ -> Result<()> {
+ if delete_message_days > 7 {
+ return Err(Error::Client(ClientError::DeleteMessageDaysAmount(delete_message_days)));
+ }
+
+ self.id.ban(user.into(), delete_message_days)
+ }
+
+ /// Creates a [`GuildChannel`] in the guild.
+ ///
+ /// Refer to [`rest::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);
+ /// ```
+ ///
+ /// [`GuildChannel`]: struct.GuildChannel.html
+ /// [`rest::create_channel`]: rest/fn.create_channel.html
+ /// [Manage Channels]: permissions/constant.MANAGE_CHANNELS.html
+ #[inline]
+ pub fn create_channel(&self, name: &str, kind: ChannelType) -> Result<Channel> {
+ self.id.create_channel(name, kind)
+ }
+
+ /// 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`]: ../utils/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) -> Result<Emoji> {
+ self.id.create_emoji(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) -> Result<()>
+ where I: Into<IntegrationId> {
+ self.id.create_integration(integration_id, 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 [`ClientError::InvalidPermissions`]
+ /// if the current user does not have permission to perform bans.
+ ///
+ /// [`ClientError::InvalidPermissions`]: ../client/enum.ClientError.html#variant.InvalidPermissions
+ /// [`Guild::create_role`]: struct.Guild.html#method.create_role
+ /// [Manage Roles]: permissions/constants.MANAGE_ROLES.html
+ #[inline]
+ pub fn create_role<F: FnOnce(EditRole) -> EditRole>(&self, f: F) -> Result<Role> {
+ self.id.create_role(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) -> Result<PartialGuild> {
+ self.id.delete()
+ }
+
+ /// 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) -> Result<()> {
+ self.id.delete_emoji(emoji_id)
+ }
+
+ /// 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) -> Result<()> {
+ self.id.delete_integration(integration_id)
+ }
+
+ /// 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) -> Result<()> {
+ self.id.delete_role(role_id)
+ }
+
+ /// Edits the current guild with new data where specified.
+ ///
+ /// Refer to [`Guild::edit`] for more information.
+ ///
+ /// **Note**: Requires the current user to have the [Manage Guild]
+ /// permission.
+ ///
+ /// [`Context::edit_guild`]: ../client/struct.Context.html#method.edit_guild
+ /// [Manage Guild]: permissions/constants.MANAGE_GUILD.html
+ pub fn edit<F>(&mut self, f: F) -> Result<()>
+ where F: FnOnce(EditGuild) -> EditGuild {
+ match self.id.edit(f) {
+ Ok(guild) => {
+ self.afk_channel_id = guild.afk_channel_id;
+ self.afk_timeout = guild.afk_timeout;
+ self.default_message_notifications = guild.default_message_notifications;
+ self.emojis = guild.emojis;
+ self.features = guild.features;
+ self.icon = guild.icon;
+ self.mfa_level = guild.mfa_level;
+ self.name = guild.name;
+ self.owner_id = guild.owner_id;
+ self.region = guild.region;
+ self.roles = guild.roles;
+ self.splash = guild.splash;
+ self.verification_level = guild.verification_level;
+
+ Ok(())
+ },
+ Err(why) => Err(why),
+ }
+ }
+
+ /// 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) -> Result<Emoji> {
+ self.id.edit_emoji(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
+ /// 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) -> Result<()>
+ where F: FnOnce(EditMember) -> EditMember, U: Into<UserId> {
+ self.id.edit_member(user_id, 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 [`ClientError::InvalidPermissions`]
+ /// if the current user does not have permission to change their own
+ /// nickname.
+ ///
+ /// [`ClientError::InvalidPermissions`]: ../client/enum.ClientError.html#variant.InvalidPermissions
+ /// [Change Nickname]: permissions/constant.CHANGE_NICKNAME.html
+ #[inline]
+ pub fn edit_nickname(&self, new_nickname: Option<&str>) -> Result<()> {
+ self.id.edit_nickname(new_nickname)
+ }
+
+ /// Gets a partial amount of guild data by its Id.
+ ///
+ /// Requires that the current user be in the guild.
+ #[inline]
+ pub fn get<G: Into<GuildId>>(guild_id: G) -> Result<PartialGuild> {
+ guild_id.into().get()
+ }
+
+ /// Gets a list of the guild's bans.
+ ///
+ /// Requires the [Ban Members] permission.
+ #[inline]
+ pub fn get_bans(&self) -> Result<Vec<Ban>> {
+ self.id.get_bans()
+ }
+
+ /// Gets all of the guild's channels over the REST API.
+ ///
+ /// [`Guild`]: struct.Guild.html
+ #[inline]
+ pub fn get_channels(&self) -> Result<HashMap<ChannelId, GuildChannel>> {
+ self.id.get_channels()
+ }
+
+ /// Gets an emoji in the guild by Id.
+ ///
+ /// Requires the [Manage Emojis] permission.
+ ///
+ /// [Manage Emojis]: permissions/constant.MANAGE_EMOJIS.html
+ #[inline]
+ pub fn get_emoji<E: Into<EmojiId>>(&self, emoji_id: E) -> Result<Emoji> {
+ self.id.get_emoji(emoji_id)
+ }
+
+ /// Gets a list of all of the guild's emojis.
+ ///
+ /// Requires the [Manage Emojis] permission.
+ ///
+ /// [Manage Emojis]: permissions/constant.MANAGE_EMOJIS.html
+ #[inline]
+ pub fn get_emojis(&self) -> Result<Vec<Emoji>> {
+ self.id.get_emojis()
+ }
+
+ /// Gets all integration of the guild.
+ ///
+ /// This performs a request over the REST API.
+ #[inline]
+ pub fn get_integrations(&self) -> Result<Vec<Integration>> {
+ self.id.get_integrations()
+ }
+
+ /// Gets all of the guild's invites.
+ ///
+ /// Requires the [Manage Guild] permission.
+ ///
+ /// [Manage Guild]: permissions/struct.MANAGE_GUILD.html
+ #[inline]
+ pub fn get_invites(&self) -> Result<Vec<RichInvite>> {
+ self.id.get_invites()
+ }
+
+ /// Gets a user's [`Member`] for the guild by Id.
+ ///
+ /// [`Guild`]: struct.Guild.html
+ /// [`Member`]: struct.Member.html
+ pub fn get_member<U: Into<UserId>>(&self, user_id: U) -> Result<Member> {
+ self.id.get_member(user_id)
+ }
+
+ /// 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 get_members<U>(&self, limit: Option<u64>, after: Option<U>)
+ -> Result<Vec<Member>> where U: Into<UserId> {
+ self.id.get_members(limit, after)
+ }
+
+ /// 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 get_prune_count(&self, days: u16) -> Result<GuildPrune> {
+ self.id.get_prune_count(days)
+ }
+
+ /// 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) -> Result<()> {
+ self.id.kick(user_id)
+ }
+
+ /// Returns a formatted URL of the guild's icon, if the guild has an icon.
+ pub fn icon_url(&self) -> Option<String> {
+ self.icon.as_ref().map(|icon|
+ format!(cdn!("/icons/{}/{}.webp"), self.id, icon))
+ }
+
+ /// Leaves the guild.
+ #[inline]
+ pub fn leave(&self) -> Result<PartialGuild> {
+ self.id.leave()
+ }
+
+ /// 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)
+ -> Result<()> where C: Into<ChannelId>, U: Into<UserId> {
+ self.id.move_member(user_id, channel_id)
+ }
+
+ /// Performs a search request to the API for the guild's [`Message`]s.
+ ///
+ /// This will search all of the guild's [`Channel`]s at once, that you have
+ /// the [Read Message History] permission to. Use [`search_channels`] to
+ /// specify a list of [channel][`GuildChannel`]s to search, where all other
+ /// channels will be excluded.
+ ///
+ /// Refer to the documentation for the [`Search`] builder for examples and
+ /// more information.
+ ///
+ /// **Note**: Bot users can not search.
+ ///
+ /// # Errors
+ ///
+ /// If the `cache` is enabled, returns a
+ /// [`ClientError::InvalidOperationAsBot`] if the current user is a bot.
+ ///
+ /// [`ClientError::InvalidOperationAsBot`]: ../client/enum.ClientError.html#variant.InvalidOperationAsBot
+ /// [`Channel`]: enum.Channel.html
+ /// [`GuildChannel`]: struct.GuildChannel.html
+ /// [`Message`]: struct.Message.html
+ /// [`Search`]: ../utils/builder/struct.Search.html
+ /// [`search_channels`]: #method.search_channels
+ /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
+ pub fn search<F>(&self, f: F) -> Result<SearchResult>
+ where F: FnOnce(Search) -> Search {
+ #[cfg(feature="cache")]
+ {
+ if CACHE.read().unwrap().user.bot {
+ return Err(Error::Client(ClientError::InvalidOperationAsBot));
+ }
+ }
+
+ self.id.search(f)
+ }
+
+ /// Performs a search request to the API for the guild's [`Message`]s in
+ /// given channels.
+ ///
+ /// This will search all of the messages in the guild's provided
+ /// [`Channel`]s by Id that you have the [Read Message History] permission
+ /// to. Use [`search`] to search all of a guild's [channel][`GuildChannel`]s
+ /// at once.
+ ///
+ /// Refer to the documentation for the [`Search`] builder for examples and
+ /// more information.
+ ///
+ /// **Note**: Bot users can not search.
+ ///
+ /// # Errors
+ ///
+ /// If the `cache` is enabled, returns a
+ /// [`ClientError::InvalidOperationAsBot`] if the current user is a bot.
+ ///
+ /// [`ClientError::InvalidOperationAsBot`]: ../client/enum.ClientError.html#variant.InvalidOperationAsBot
+ /// [`Channel`]: enum.Channel.html
+ /// [`GuildChannel`]: struct.GuildChannel.html
+ /// [`Message`]: struct.Message.html
+ /// [`Search`]: ../utils/builder/struct.Search.html
+ /// [`search`]: #method.search
+ /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
+ pub fn search_channels<F>(&self, channel_ids: &[ChannelId], f: F)
+ -> Result<SearchResult> where F: FnOnce(Search) -> Search {
+ #[cfg(feature="cache")]
+ {
+ if CACHE.read().unwrap().user.bot {
+ return Err(Error::Client(ClientError::InvalidOperationAsBot));
+ }
+ }
+
+ self.id.search_channels(channel_ids, f)
+ }
+
+ /// Returns the formatted URL of the guild's splash image, if one exists.
+ pub fn splash_url(&self) -> Option<String> {
+ self.icon.as_ref().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: Into<IntegrationId>>(&self, integration_id: I) -> Result<()> {
+ self.id.start_integration_sync(integration_id)
+ }
+
+ /// 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) -> Result<()> {
+ self.id.unban(user_id)
+ }
+
+ /// Retrieves the guild's webhooks.
+ ///
+ /// **Note**: Requires the [Manage Webhooks] permission.
+ ///
+ /// [Manage Webhooks]: permissions/constant.MANAGE_WEBHOOKS.html
+ #[inline]
+ pub fn webhooks(&self) -> Result<Vec<Webhook>> {
+ self.id.webhooks()
+ }
+}
+
impl PossibleGuild<Guild> {
#[doc(hidden)]
pub fn decode(value: Value) -> Result<Self> {
@@ -1240,13 +2431,36 @@ impl Role {
/// **Note** Requires the [Manage Roles] permission.
///
/// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
- #[cfg(all(feature="cache", feature="methods"))]
+ #[cfg(feature="cache")]
pub fn delete(&self) -> Result<()> {
let guild_id = self.find_guild()?;
rest::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,ignore
+ /// context.edit_role(guild_id, role_id, |r| r
+ /// .hoist(true));
+ /// ```
+ ///
+ /// [`Role`]: struct.Role.html
+ /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
+ #[cfg(feature="cache")]
+ pub fn edit_role<F: FnOnce(EditRole) -> EditRole>(&self, f: F) -> Result<Role> {
+ match self.find_guild() {
+ Ok(guild_id) => guild_id.edit_role(self.id, f),
+ Err(why) => Err(why),
+ }
+ }
+
/// Searches the cache for the guild that owns the role.
///
/// # Errors
@@ -1255,7 +2469,7 @@ impl Role {
/// that contains the role.
///
/// [`ClientError::GuildNotFound`]: ../client/enum.ClientError.html#variant.GuildNotFound
- #[cfg(all(feature="cache", feature="methods"))]
+ #[cfg(feature="cache")]
pub fn find_guild(&self) -> Result<GuildId> {
CACHE.read()
.unwrap()
@@ -1267,6 +2481,7 @@ impl Role {
}
/// Check that the role has the given permission.
+ #[inline]
pub fn has_permission(&self, permission: Permissions) -> bool {
self.permissions.contains(permission)
}
@@ -1317,3 +2532,34 @@ impl PartialOrd for Role {
Some(self.cmp(other))
}
}
+
+impl RoleId {
+ /// Search the cache for the role.
+ #[cfg(feature="cache")]
+ pub fn find(&self) -> Option<Role> {
+ CACHE.read()
+ .unwrap()
+ .guilds
+ .values()
+ .find(|guild| guild.roles.contains_key(self))
+ .map(|guild| guild.roles.get(self))
+ .and_then(|v| match v {
+ Some(v) => Some(v),
+ None => None,
+ })
+ .cloned()
+ }
+}
+
+impl fmt::Display for RoleId {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(&self.0, f)
+ }
+}
+
+impl From<Role> for RoleId {
+ /// Gets the Id of a role.
+ fn from(role: Role) -> RoleId {
+ role.id
+ }
+}
diff --git a/src/model/id.rs b/src/model/id.rs
deleted file mode 100644
index 17fd29c..0000000
--- a/src/model/id.rs
+++ /dev/null
@@ -1,238 +0,0 @@
-use super::*;
-use std::fmt;
-
-#[cfg(all(feature="cache", feature="methods"))]
-use ::client::CACHE;
-#[cfg(feature="methods")]
-use ::client::rest;
-#[cfg(feature="methods")]
-use ::internal::prelude::*;
-
-impl ChannelId {
- /// Search the cache for the channel with the Id.
- #[cfg(all(feature="cache", feature="methods"))]
- pub fn find(&self) -> Option<Channel> {
- CACHE.read().unwrap().get_channel(*self).map(|x| x.clone_inner())
- }
-
- /// Search the cache for the channel. If it can't be found, the channel is
- /// requested over REST.
- #[cfg(feature="methods")]
- pub fn get(&self) -> Result<Channel> {
- #[cfg(feature="cache")]
- {
- if let Some(channel) = CACHE.read().unwrap().get_channel(*self) {
- return Ok(channel.clone_inner());
- }
- }
-
- rest::get_channel(self.0)
- }
-
- /// Retrieves the channel's webhooks.
- ///
- /// **Note**: Requires the [Manage Webhooks] permission.
- ///
- /// [Manage Webhooks]: permissions/constant.MANAGE_WEBHOOKS.html
- #[cfg(feature="methods")]
- pub fn webhooks(&self) -> Result<Vec<Webhook>> {
- rest::get_channel_webhooks(self.0)
- }
-}
-
-impl From<Channel> for ChannelId {
- /// Gets the Id of a `Channel`.
- fn from(channel: Channel) -> ChannelId {
- match channel {
- Channel::Group(group) => group.channel_id,
- Channel::Guild(channel) => channel.id,
- Channel::Private(channel) => channel.id,
- }
- }
-}
-
-impl From<PrivateChannel> for ChannelId {
- /// Gets the Id of a private channel.
- fn from(private_channel: PrivateChannel) -> ChannelId {
- private_channel.id
- }
-}
-
-impl From<GuildChannel> for ChannelId {
- /// Gets the Id of a guild channel.
- fn from(public_channel: GuildChannel) -> ChannelId {
- public_channel.id
- }
-}
-
-impl From<Emoji> for EmojiId {
- /// Gets the Id of an `Emoji`.
- fn from(emoji: Emoji) -> EmojiId {
- emoji.id
- }
-}
-
-impl GuildId {
- /// Search the cache for the guild.
- #[cfg(all(feature="cache", feature="methods"))]
- pub fn find(&self) -> Option<Guild> {
- CACHE.read().unwrap().get_guild(*self).cloned()
- }
-
- /// Requests the guild over REST.
- ///
- /// Note that this will not be a complete guild, as REST does not send
- /// all data with a guild retrieval.
- #[cfg(feature="methods")]
- pub fn get(&self) -> Result<PartialGuild> {
- rest::get_guild(self.0)
- }
-
- /// Retrieves the guild's webhooks.
- ///
- /// **Note**: Requires the [Manage Webhooks] permission.
- ///
- /// [Manage Webhooks]: permissions/constant.MANAGE_WEBHOOKS.html
- #[cfg(feature="methods")]
- pub fn webhooks(&self) -> Result<Vec<Webhook>> {
- rest::get_guild_webhooks(self.0)
- }
-}
-
-impl From<PartialGuild> for GuildId {
- /// Gets the Id of a partial guild.
- fn from(guild: PartialGuild) -> GuildId {
- guild.id
- }
-}
-
-impl From<GuildInfo> for GuildId {
- /// Gets the Id of Guild information struct.
- fn from(guild_info: GuildInfo) -> GuildId {
- guild_info.id
- }
-}
-
-impl From<InviteGuild> for GuildId {
- /// Gets the Id of Invite Guild struct.
- fn from(invite_guild: InviteGuild) -> GuildId {
- invite_guild.id
- }
-}
-
-impl From<Guild> for GuildId {
- /// Gets the Id of Guild.
- fn from(live_guild: Guild) -> GuildId {
- live_guild.id
- }
-}
-
-impl From<Integration> for IntegrationId {
- /// Gets the Id of integration.
- fn from(integration: Integration) -> IntegrationId {
- integration.id
- }
-}
-
-impl From<Message> for MessageId {
- /// Gets the Id of a `Message`.
- fn from(message: Message) -> MessageId {
- message.id
- }
-}
-
-impl From<Role> for RoleId {
- /// Gets the Id of a `Role`.
- fn from(role: Role) -> RoleId {
- role.id
- }
-}
-
-impl RoleId {
- /// Search the cache for the role.
- #[cfg(all(feature="cache", feature="methods"))]
- pub fn find(&self) -> Option<Role> {
- CACHE.read()
- .unwrap()
- .guilds
- .values()
- .find(|guild| guild.roles.contains_key(self))
- .map(|guild| guild.roles.get(self))
- .and_then(|v| match v {
- Some(v) => Some(v),
- None => None,
- })
- .cloned()
- }
-}
-
-impl UserId {
- /// Search the cache for the user with the Id.
- #[cfg(all(feature="cache", feature="methods"))]
- pub fn find(&self) -> Option<User> {
- CACHE.read().unwrap().get_user(*self).cloned()
- }
-}
-
-impl From<CurrentUser> for UserId {
- /// Gets the Id of a `CurrentUser` struct.
- fn from(current_user: CurrentUser) -> UserId {
- current_user.id
- }
-}
-
-impl From<Member> for UserId {
- /// Gets the Id of a `Member`.
- fn from(member: Member) -> UserId {
- member.user.id
- }
-}
-
-impl From<User> for UserId {
- /// Gets the Id of a `User`.
- fn from(user: User) -> UserId {
- user.id
- }
-}
-
-impl fmt::Display for UserId {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- fmt::Display::fmt(&self.0, f)
- }
-}
-
-impl fmt::Display for RoleId {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- fmt::Display::fmt(&self.0, f)
- }
-}
-
-impl fmt::Display for ChannelId {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- fmt::Display::fmt(&self.0, f)
- }
-}
-
-impl fmt::Display for GuildId {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- fmt::Display::fmt(&self.0, f)
- }
-}
-
-impl fmt::Display for EmojiId {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- fmt::Display::fmt(&self.0, f)
- }
-}
-
-impl WebhookId {
- /// Retrieves the webhook by the Id.
- ///
- /// **Note**: Requires the [Manage Webhooks] permission.
- ///
- /// [Manage Webhooks]: permissions/constant.MANAGE_WEBHOOKS.html
- #[cfg(feature="methods")]
- pub fn webhooks(&self) -> Result<Webhook> {
- rest::get_webhook(self.0)
- }
-}
diff --git a/src/model/invite.rs b/src/model/invite.rs
index adfba60..47ae28a 100644
--- a/src/model/invite.rs
+++ b/src/model/invite.rs
@@ -1,12 +1,15 @@
use super::{Invite, RichInvite};
use ::client::rest;
use ::internal::prelude::*;
+use ::model::ChannelId;
+use ::utils::builder::CreateInvite;
+use ::utils;
#[cfg(feature="cache")]
use super::permissions;
-#[cfg(all(feature="cache", feature="methods"))]
-use super::utils;
-#[cfg(feature = "cache")]
+#[cfg(feature="cache")]
+use super::utils as model_utils;
+#[cfg(feature="cache")]
use ::client::CACHE;
impl Invite {
@@ -26,11 +29,10 @@ impl Invite {
/// [`ClientError::InvalidOperationAsBot`] if the current user does not have
/// the required [permission].
///
- /// [`ClientError::InvalidOperationAsBot`]: enum.ClientError.html#variant.InvalidOperationAsBot
+ /// [`ClientError::InvalidOperationAsBot`]: ../client/enum.ClientError.html#variant.InvalidOperationAsBot
/// [`Guild`]: struct.Guild.html
/// [`rest::accept_invite`]: ../client/rest/fn.accept_invite.html
/// [permission]: permissions/index.html
- #[cfg(feature="methods")]
pub fn accept(&self) -> Result<Invite> {
#[cfg(feature="cache")]
{
@@ -42,6 +44,39 @@ impl Invite {
rest::accept_invite(&self.code)
}
+ /// Creates an invite for a [`GuildChannel`], providing a builder so that
+ /// fields may optionally be set.
+ ///
+ /// See the documentation for the [`CreateInvite`] builder for information
+ /// on how to use this and the default values that it provides.
+ ///
+ /// Requires the [Create Invite] permission.
+ ///
+ /// # Errors
+ ///
+ /// If the `cache` is enabled, returns a [`ClientError::InvalidPermissions`]
+ /// if the current user does not have the required [permission].
+ ///
+ /// [`CreateInvite`]: ../utils/builder/struct.CreateInvite.html
+ /// [`GuildChannel`]: struct.GuildChannel.html
+ /// [Create Invite]: permissions/constant.CREATE_INVITE.html
+ /// [permission]: permissions/index.html
+ pub fn create<C, F>(channel_id: C, f: F) -> Result<RichInvite>
+ where C: Into<ChannelId>, F: FnOnce(CreateInvite) -> CreateInvite {
+ let channel_id = channel_id.into();
+
+ #[cfg(feature="cache")]
+ {
+ let req = permissions::CREATE_INVITE;
+
+ if !model_utils::user_has_perms(channel_id, req)? {
+ return Err(Error::Client(ClientError::InvalidPermissions(req)));
+ }
+ }
+
+ rest::create_invite(channel_id.0, f(CreateInvite::default()).0.build())
+ }
+
/// Deletes the invite.
///
/// **Note**: Requires the [Manage Guild] permission.
@@ -54,19 +89,23 @@ impl Invite {
/// [`ClientError::InvalidPermissions`]: ../client/enum.ClientError.html#variant.InvalidPermissions
/// [Manage Guild]: permissions/constant.MANAGE_GUILD.html
/// [permission]: permissions/index.html
- #[cfg(feature="methods")]
pub fn delete(&self) -> Result<Invite> {
#[cfg(feature="cache")]
{
let req = permissions::MANAGE_GUILD;
- if !utils::user_has_perms(self.channel.id, req)? {
+ if !model_utils::user_has_perms(self.channel.id, req)? {
return Err(Error::Client(ClientError::InvalidPermissions(req)));
}
}
rest::delete_invite(&self.code)
}
+
+ /// Gets the information about an invite.
+ pub fn get(code: &str) -> Result<Invite> {
+ rest::get_invite(utils::parse_invite(code))
+ }
}
impl RichInvite {
@@ -86,10 +125,9 @@ impl RichInvite {
/// [`ClientError::InvalidOperationAsBot`] if the current user is a bot
/// user.
///
- /// [`ClientError::InvalidOperationAsBot`]: enum.ClientError.html#variant.InvalidOperationAsBot
+ /// [`ClientError::InvalidOperationAsBot`]: ../client/enum.ClientError.html#variant.InvalidOperationAsBot
/// [`Guild`]: struct.Guild.html
/// [`rest::accept_invite`]: ../client/rest/fn.accept_invite.html
- #[cfg(feature="methods")]
pub fn accept(&self) -> Result<Invite> {
#[cfg(feature="cache")]
{
@@ -118,13 +156,12 @@ impl RichInvite {
/// [`rest::delete_invite`]: ../client/rest/fn.delete_invite.html
/// [Manage Guild]: permissions/constant.MANAGE_GUILD.html
/// [permission]: permissions/index.html
- #[cfg(feature="methods")]
pub fn delete(&self) -> Result<Invite> {
#[cfg(feature="cache")]
{
let req = permissions::MANAGE_GUILD;
- if !utils::user_has_perms(self.channel.id, req)? {
+ if !model_utils::user_has_perms(self.channel.id, req)? {
return Err(Error::Client(ClientError::InvalidPermissions(req)));
}
}
diff --git a/src/model/misc.rs b/src/model/misc.rs
index f3632a5..eaae890 100644
--- a/src/model/misc.rs
+++ b/src/model/misc.rs
@@ -78,7 +78,7 @@ impl Mentionable for User {
}
}
-#[cfg(all(feature="cache", feature="methods"))]
+#[cfg(feature="cache")]
impl FromStr for User {
type Err = ();
@@ -103,7 +103,7 @@ impl FromStr for UserId {
}
}
-#[cfg(all(feature="cache", feature="methods"))]
+#[cfg(feature="cache")]
impl FromStr for Role {
type Err = ();
@@ -130,7 +130,6 @@ impl FromStr for RoleId {
impl EmojiIdentifier {
/// Generates a URL to the emoji's image.
- #[cfg(feature="methods")]
#[inline]
pub fn url(&self) -> String {
format!(cdn!("/emojis/{}.png"), self.id)
@@ -153,7 +152,7 @@ impl FromStr for ChannelId {
}
}
-#[cfg(all(feature="cache", feature="methods"))]
+#[cfg(feature="cache")]
impl FromStr for Channel {
type Err = ();
diff --git a/src/model/mod.rs b/src/model/mod.rs
index 5aad290..c2883ce 100644
--- a/src/model/mod.rs
+++ b/src/model/mod.rs
@@ -23,26 +23,18 @@ pub mod permissions;
mod channel;
mod gateway;
mod guild;
-mod id;
+mod invite;
mod misc;
mod user;
-
-#[cfg(feature="methods")]
-mod invite;
-#[cfg(feature="methods")]
mod webhook;
pub use self::channel::*;
pub use self::gateway::*;
pub use self::guild::*;
-pub use self::id::*;
+pub use self::invite::*;
pub use self::misc::*;
pub use self::permissions::Permissions;
pub use self::user::*;
-
-#[cfg(feature="methods")]
-pub use self::invite::*;
-#[cfg(feature="methods")]
pub use self::webhook::*;
use self::utils::*;
diff --git a/src/model/user.rs b/src/model/user.rs
index 8a2dd45..4eaf65e 100644
--- a/src/model/user.rs
+++ b/src/model/user.rs
@@ -1,32 +1,26 @@
-use std::fmt;
+use serde_json::builder::ObjectBuilder;
+use std::{fmt, mem};
use super::utils::{into_map, into_string, remove};
use super::{
CurrentUser,
FriendSourceFlags,
GuildContainer,
GuildId,
+ GuildInfo,
+ Member,
+ Message,
+ PrivateChannel,
RoleId,
UserSettings,
User,
+ UserId,
};
-use ::internal::prelude::*;
-use ::utils::decode_array;
-use ::model::misc::Mentionable;
-
-#[cfg(feature="methods")]
-use serde_json::builder::ObjectBuilder;
-#[cfg(feature="methods")]
-use std::mem;
-#[cfg(feature="methods")]
-use super::Message;
-#[cfg(feature="methods")]
use time::Timespec;
-#[cfg(feature="methods")]
use ::client::rest::{self, GuildPagination};
-#[cfg(feature="methods")]
-use super::GuildInfo;
-#[cfg(feature="methods")]
+use ::internal::prelude::*;
+use ::model::misc::Mentionable;
use ::utils::builder::EditProfile;
+use ::utils::decode_array;
#[cfg(feature="cache")]
use ::client::CACHE;
@@ -49,7 +43,6 @@ impl CurrentUser {
}
/// Returns the DiscordTag of a User.
- #[cfg(feature="methods")]
pub fn distinct(&self) -> String {
format!("{}#{}", self.name, self.discriminator)
}
@@ -75,7 +68,6 @@ impl CurrentUser {
/// .edit(|p| p
/// .avatar(Some(&avatar)));
/// ```
- #[cfg(feature="methods")]
pub fn edit<F>(&mut self, f: F) -> Result<()>
where F: FnOnce(EditProfile) -> EditProfile {
let mut map = ObjectBuilder::new()
@@ -86,11 +78,9 @@ impl CurrentUser {
map = map.insert("email", email)
}
- let edited = f(EditProfile(map)).0.build();
-
- match rest::edit_profile(edited) {
+ match rest::edit_profile(f(EditProfile(map)).0.build()) {
Ok(new) => {
- mem::replace(self, new);
+ let _ = mem::replace(self, new);
Ok(())
},
@@ -99,9 +89,9 @@ impl CurrentUser {
}
/// Gets a list of guilds that the current user is in.
- #[cfg(feature="methods")]
+ #[inline]
pub fn guilds(&self) -> Result<Vec<GuildInfo>> {
- rest::get_guilds(GuildPagination::After(GuildId(0)), 100)
+ rest::get_guilds(GuildPagination::After(GuildId(1)), 100)
}
/// Returns a static formatted URL of the user's icon, if one exists.
@@ -130,14 +120,22 @@ impl User {
})
}
+ /// 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) -> Result<PrivateChannel> {
+ self.id.create_dm_channel()
+ }
+
/// Returns the DiscordTag of a User.
- #[cfg(feature="methods")]
+ #[inline]
pub fn distinct(&self) -> String {
format!("{}#{}", self.name, self.discriminator)
}
/// Retrieves the time that this user was created at.
- #[cfg(feature="methods")]
#[inline]
pub fn created_at(&self) -> Timespec {
self.id.created_at()
@@ -162,10 +160,26 @@ impl User {
Ok(cdn!("/embed/avatars/{}.png", self.discriminator.parse::<u16>()? % 5u16).to_owned())
}
- /// Send a direct message to a user. This will create or retrieve the
- /// PrivateChannel over REST if one is not already in the cache, and then
- /// send a message to it.
- #[cfg(feature="methods")]
+ /// Deletes a profile note from a user.
+ #[inline]
+ pub fn delete_note(&self) -> Result<()> {
+ self.id.delete_note()
+ }
+
+ /// 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
+ ///
+ /// Sending a message:
+ ///
+ /// ```rust,ignore
+ /// // assuming you are in a context
+ /// let _ = context.message.author.dm("Hello!");
+ /// ```
+ ///
+ /// [`PrivateChannel`]: struct.PrivateChannel.html
+ /// [`User::dm`]: struct.User.html#method.dm
pub fn direct_message(&self, content: &str)
-> Result<Message> {
let private_channel_id = feature_cache! {{
@@ -205,12 +219,61 @@ impl User {
/// This is an alias of [direct_message].
///
/// [direct_message]: #method.direct_message
- #[cfg(feature="methods")]
#[inline]
pub fn dm(&self, content: &str) -> Result<Message> {
self.direct_message(content)
}
+ /// Edits the note that the current user has set for another user.
+ ///
+ /// Use [`delete_note`] to remove a note.
+ ///
+ /// **Note**: Requires that the current user be a user account.
+ ///
+ /// # Examples
+ ///
+ /// Set a note for a message's author:
+ ///
+ /// ```rust,ignore
+ /// // assuming a `message` has been bound
+ /// let _ = context.edit_note(message.author, "test note");
+ /// ```
+ ///
+ /// # Errors
+ ///
+ /// If the `cache` is enabled, returns a
+ /// [`ClientError::InvalidOperationAsBot`] if the current user is a bot
+ /// user.
+ ///
+ /// [`ClientError::InvalidOperationAsBot`]: ../client/enum.ClientError.html#variant.InvalidOperationAsBot
+ /// [`delete_note`]: #method.delete_note
+ #[inline]
+ pub fn edit_note(&self, note: &str) -> Result<()> {
+ self.id.edit_note(note)
+ }
+
+ /// Gets a user by its Id over the REST API.
+ ///
+ /// **Note**: The current user must be a bot user.
+ ///
+ /// # Errors
+ ///
+ /// If the `cache` is enabled, returns a
+ /// [`ClientError::InvalidOperationAsUser`] if the current user is not a bot
+ /// user.
+ ///
+ /// [`ClientError::InvalidOperationAsUser`]: ../client/enum.ClientError.html#variant.InvalidOperationAsUser
+ pub fn get<U: Into<UserId>>(user_id: U) -> Result<User> {
+ #[cfg(feature="cache")]
+ {
+ if !CACHE.read().unwrap().user.bot {
+ return Err(Error::Client(ClientError::InvalidOperationAsUser));
+ }
+ }
+
+ user_id.into().get()
+ }
+
/// 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`].
@@ -244,13 +307,16 @@ impl User {
match guild.into() {
GuildContainer::Guild(guild) => {
- guild.roles.get(&role_id).is_some()
+ guild.roles.contains_key(&role_id)
},
- GuildContainer::Id(guild_id) => {
+ GuildContainer::Id(_guild_id) => {
feature_cache! {{
- let cache = CACHE.read().unwrap();
-
- cache.get_role(guild_id, role_id).is_some()
+ CACHE.read()
+ .unwrap()
+ .guilds
+ .get(&_guild_id)
+ .map(|g| g.roles.contains_key(&role_id))
+ .unwrap_or(false)
} else {
true
}}
@@ -275,6 +341,82 @@ impl fmt::Display for User {
}
}
+impl UserId {
+ /// 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
+ pub fn create_dm_channel(&self) -> Result<PrivateChannel> {
+ let map = ObjectBuilder::new().insert("recipient_id", self.0).build();
+
+ rest::create_private_channel(map)
+ }
+
+ /// Deletes a profile note from a user.
+ pub fn delete_note(&self) -> Result<()> {
+ let map = ObjectBuilder::new().insert("note", "").build();
+
+ rest::edit_note(self.0, map)
+ }
+
+ /// Edits the note that the current user has set for another user.
+ ///
+ /// Use [`delete_note`] to remove a note.
+ ///
+ /// Refer to the documentation for [`User::edit_note`] for more information.
+ ///
+ /// **Note**: Requires that the current user be a user account.
+ ///
+ /// [`delete_note`]: #method.delete_note
+ /// [`User::edit_note`]: struct.User.html#method.edit_note
+ pub fn edit_note(&self, note: &str) -> Result<()> {
+ let map = ObjectBuilder::new().insert("note", note).build();
+
+ rest::edit_note(self.0, map)
+ }
+
+ /// Search the cache for the user with the Id.
+ #[cfg(feature="cache")]
+ pub fn find(&self) -> Option<User> {
+ CACHE.read().unwrap().get_user(*self).cloned()
+ }
+
+ /// Gets a user by its Id over the REST API.
+ ///
+ /// **Note**: The current user must be a bot user.
+ #[inline]
+ pub fn get(&self) -> Result<User> {
+ rest::get_user(self.0)
+ }
+}
+
+impl From<CurrentUser> for UserId {
+ /// Gets the Id of a `CurrentUser` struct.
+ fn from(current_user: CurrentUser) -> UserId {
+ current_user.id
+ }
+}
+
+impl From<Member> for UserId {
+ /// Gets the Id of a `Member`.
+ fn from(member: Member) -> UserId {
+ member.user.id
+ }
+}
+
+impl From<User> for UserId {
+ /// Gets the Id of a `User`.
+ fn from(user: User) -> UserId {
+ user.id
+ }
+}
+
+impl fmt::Display for UserId {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(&self.0, f)
+ }
+}
+
impl UserSettings {
#[doc(hidden)]
pub fn decode(value: Value) -> Result<Option<UserSettings>> {
diff --git a/src/model/utils.rs b/src/model/utils.rs
index 71b4a52..dee9a08 100644
--- a/src/model/utils.rs
+++ b/src/model/utils.rs
@@ -18,11 +18,11 @@ use super::{
use ::internal::prelude::*;
use ::utils::{decode_array, into_array};
-#[cfg(all(feature="cache", feature="methods"))]
+#[cfg(feature="cache")]
use super::permissions::{self, Permissions};
-#[cfg(all(feature="cache", feature="methods"))]
+#[cfg(feature="cache")]
use ::client::CACHE;
-#[cfg(all(feature="cache", feature="methods"))]
+#[cfg(feature="cache")]
use ::ext::cache::ChannelRef;
#[macro_escape]
@@ -293,7 +293,7 @@ pub fn remove(map: &mut BTreeMap<String, Value>, key: &str) -> Result<Value> {
})
}
-#[cfg(all(feature="cache", feature="methods"))]
+#[cfg(feature="cache")]
pub fn user_has_perms(channel_id: ChannelId,
mut permissions: Permissions)
-> Result<bool> {
diff --git a/src/model/webhook.rs b/src/model/webhook.rs
index 9d3a393..f1a664d 100644
--- a/src/model/webhook.rs
+++ b/src/model/webhook.rs
@@ -1,6 +1,6 @@
use serde_json::builder::ObjectBuilder;
use std::mem;
-use super::{Message, Webhook};
+use super::{Message, Webhook, WebhookId};
use ::utils::builder::ExecuteWebhook;
use ::client::rest;
use ::internal::prelude::*;
@@ -12,7 +12,7 @@ impl Webhook {
/// authentication is not required.
///
/// [`rest::delete_webhook_with_token`]: ../client/rest/fn.delete_webhook_with_token.html
- #[cfg(feature="methods")]
+ #[inline]
pub fn delete(&self) -> Result<()> {
rest::delete_webhook_with_token(self.id.0, &self.token)
}
@@ -63,7 +63,6 @@ impl Webhook {
///
/// [`rest::edit_webhook`]: ../client/rest/fn.edit_webhook.html
/// [`rest::edit_webhook_with_token`]: ../client/rest/fn.edit_webhook_with_token.html
- #[cfg(feature="methods")]
pub fn edit(&mut self, name: Option<&str>, avatar: Option<&str>)
-> Result<()> {
if name.is_none() && avatar.is_none() {
@@ -84,9 +83,7 @@ impl Webhook {
map = map.insert("name", name);
}
- let map = map.build();
-
- match rest::edit_webhook_with_token(self.id.0, &self.token, map) {
+ match rest::edit_webhook_with_token(self.id.0, &self.token, map.build()) {
Ok(replacement) => {
mem::replace(self, replacement);
@@ -143,12 +140,9 @@ impl Webhook {
/// .embeds(vec![embed]))
/// .expect("Error executing");
/// ```
- #[cfg(feature="methods")]
- pub fn execute<F>(&self, f: F) -> Result<Message>
- where F: FnOnce(ExecuteWebhook) -> ExecuteWebhook {
- let map = f(ExecuteWebhook::default()).0.build();
-
- rest::execute_webhook(self.id.0, &self.token, map)
+ #[inline]
+ pub fn execute<F: FnOnce(ExecuteWebhook) -> ExecuteWebhook>(&self, f: F) -> Result<Message> {
+ rest::execute_webhook(self.id.0, &self.token, f(ExecuteWebhook::default()).0.build())
}
/// Retrieves the latest information about the webhook, editing the
@@ -158,7 +152,6 @@ impl Webhook {
/// authentication is not required.
///
/// [`rest::get_webhook_with_token`]: ../client/rest/fn.get_webhook_with_token.html
- #[cfg(feature="methods")]
pub fn refresh(&mut self) -> Result<()> {
match rest::get_webhook_with_token(self.id.0, &self.token) {
Ok(replacement) => {
@@ -170,3 +163,15 @@ impl Webhook {
}
}
}
+
+impl WebhookId {
+ /// Retrieves the webhook by the Id.
+ ///
+ /// **Note**: Requires the [Manage Webhooks] permission.
+ ///
+ /// [Manage Webhooks]: permissions/constant.MANAGE_WEBHOOKS.html
+ #[inline]
+ pub fn get(&self) -> Result<Webhook> {
+ rest::get_webhook(self.0)
+ }
+}
diff --git a/src/utils/macros.rs b/src/utils/macros.rs
index e4aaa14..484638f 100644
--- a/src/utils/macros.rs
+++ b/src/utils/macros.rs
@@ -94,25 +94,6 @@ macro_rules! feature_framework {
}
}
-// Enable/disable check for methods
-#[cfg(feature="methods")]
-macro_rules! feature_methods {
- ($enabled:block else $disabled:block) => {
- {
- $enabled
- }
- }
-}
-
-#[cfg(not(feature="methods"))]
-macro_rules! feature_methods {
- ($enabled:block else $disabled:block) => {
- {
- $disabled
- }
- }
-}
-
// Enable/disable check for voice
#[cfg(feature="voice")]
macro_rules! feature_voice {