aboutsummaryrefslogtreecommitdiff
path: root/src/model
diff options
context:
space:
mode:
authorZeyla Hellyer <[email protected]>2018-05-28 16:34:38 -0700
committerZeyla Hellyer <[email protected]>2018-05-28 16:34:38 -0700
commit6b5f3b98084b86b00e3f7e78b5eb9512e75e78a0 (patch)
tree4011d56b63d88999eb8169e332c54f3eafe972ae /src/model
parentMake Message Builder use &mut self instead of self (diff)
parentFutures shard manager #298 (WIP) (#300) (diff)
downloadserenity-6b5f3b98084b86b00e3f7e78b5eb9512e75e78a0.tar.xz
serenity-6b5f3b98084b86b00e3f7e78b5eb9512e75e78a0.zip
Merge branch 'futures' into v0.6.x
Diffstat (limited to 'src/model')
-rw-r--r--src/model/channel/attachment.rs88
-rw-r--r--src/model/channel/channel_category.rs95
-rw-r--r--src/model/channel/channel_id.rs580
-rw-r--r--src/model/channel/embed.rs7
-rw-r--r--src/model/channel/group.rs273
-rw-r--r--src/model/channel/guild_channel.rs568
-rw-r--r--src/model/channel/message.rs421
-rw-r--r--src/model/channel/mod.rs333
-rw-r--r--src/model/channel/private_channel.rs266
-rw-r--r--src/model/channel/reaction.rs135
-rw-r--r--src/model/error.rs4
-rw-r--r--src/model/event.rs628
-rw-r--r--src/model/gateway.rs23
-rw-r--r--src/model/guild/emoji.rs142
-rw-r--r--src/model/guild/guild_id.rs526
-rw-r--r--src/model/guild/member.rs407
-rw-r--r--src/model/guild/mod.rs963
-rw-r--r--src/model/guild/partial_guild.rs391
-rw-r--r--src/model/guild/role.rs89
-rw-r--r--src/model/invite.rs136
-rw-r--r--src/model/misc.rs73
-rw-r--r--src/model/mod.rs14
-rw-r--r--src/model/permissions.rs1
-rw-r--r--src/model/user.rs498
-rw-r--r--src/model/utils.rs142
-rw-r--r--src/model/webhook.rs200
26 files changed, 335 insertions, 6668 deletions
diff --git a/src/model/channel/attachment.rs b/src/model/channel/attachment.rs
index 0530b6f..8e3f149 100644
--- a/src/model/channel/attachment.rs
+++ b/src/model/channel/attachment.rs
@@ -1,10 +1,3 @@
-#[cfg(feature = "model")]
-use hyper::Client as HyperClient;
-#[cfg(feature = "model")]
-use internal::prelude::*;
-#[cfg(feature = "model")]
-use std::io::Read;
-
/// A file uploaded with a message. Not to be confused with [`Embed`]s.
///
/// [`Embed`]: struct.Embed.html
@@ -27,7 +20,6 @@ pub struct Attachment {
pub width: Option<u64>,
}
-#[cfg(feature = "model")]
impl Attachment {
/// If this attachment is an image, then a tuple of the width and height
/// in pixels is returned.
@@ -35,84 +27,4 @@ impl Attachment {
self.width
.and_then(|width| self.height.map(|height| (width, height)))
}
-
- /// Downloads the attachment, returning back a vector of bytes.
- ///
- /// # Examples
- ///
- /// Download all of the attachments associated with a [`Message`]:
- ///
- /// ```rust,no_run
- /// use serenity::model::prelude::*;
- /// use serenity::prelude::*;
- /// use std::env;
- /// use std::fs::File;
- /// use std::io::Write;
- /// use std::path::Path;
- ///
- /// struct Handler;
- ///
- /// impl EventHandler for Handler {
- /// fn message(&self, _: Context, message: Message) {
- /// for attachment in message.attachments {
- /// let content = match attachment.download() {
- /// Ok(content) => content,
- /// Err(why) => {
- /// println!("Error downloading attachment: {:?}", why);
- /// let _ = message.channel_id.say("Error downloading attachment");
- ///
- /// return;
- /// },
- /// };
- ///
- /// let mut file = match File::create(&attachment.filename) {
- /// Ok(file) => file,
- /// Err(why) => {
- /// println!("Error creating file: {:?}", why);
- /// let _ = message.channel_id.say("Error creating file");
- ///
- /// return;
- /// },
- /// };
- ///
- /// if let Err(why) = file.write(&content) {
- /// println!("Error writing to file: {:?}", why);
- ///
- /// return;
- /// }
- ///
- /// let _ = message.channel_id.say(&format!("Saved {:?}", attachment.filename));
- /// }
- /// }
- ///
- /// fn ready(&self, _: Context, ready: Ready) {
- /// println!("{} is connected!", ready.user.name);
- /// }
- /// }
- /// let token = env::var("DISCORD_TOKEN").expect("token in environment");
- /// let mut client = Client::new(&token, Handler).unwrap();
- ///
- /// client.start().unwrap();
- /// ```
- ///
- /// # Errors
- ///
- /// Returns an [`Error::Io`] when there is a problem reading the contents
- /// of the HTTP response.
- ///
- /// Returns an [`Error::Hyper`] when there is a problem retrieving the
- /// attachment.
- ///
- /// [`Error::Hyper`]: ../enum.Error.html#variant.Hyper
- /// [`Error::Io`]: ../enum.Error.html#variant.Io
- /// [`Message`]: struct.Message.html
- pub fn download(&self) -> Result<Vec<u8>> {
- let hyper = request_client!();
- let mut response = hyper.get(&self.url).send()?;
-
- let mut bytes = vec![];
- response.read_to_end(&mut bytes)?;
-
- Ok(bytes)
- }
}
diff --git a/src/model/channel/channel_category.rs b/src/model/channel/channel_category.rs
index 7a49c7e..0fd1a69 100644
--- a/src/model/channel/channel_category.rs
+++ b/src/model/channel/channel_category.rs
@@ -1,11 +1,7 @@
use model::prelude::*;
-#[cfg(all(feature = "builder", feature = "model"))]
-use builder::EditChannel;
-#[cfg(all(feature = "builder", feature = "model"))]
-use http;
-#[cfg(all(feature = "model", feature = "utils"))]
-use utils::{self as serenity_utils, VecMap};
+#[cfg(feature = "utils")]
+use utils as serenity_utils;
/// A category of [`GuildChannel`]s.
///
@@ -37,94 +33,7 @@ pub struct ChannelCategory {
pub permission_overwrites: Vec<PermissionOverwrite>,
}
-#[cfg(feature = "model")]
impl ChannelCategory {
- /// Adds a permission overwrite to the category's channels.
- #[inline]
- pub fn create_permission(&self, target: &PermissionOverwrite) -> Result<()> {
- self.id.create_permission(target)
- }
-
- /// Deletes all permission overrides in the category from the channels.
- ///
- /// **Note**: Requires the [Manage Channel] permission.
- ///
- /// [Manage Channel]: permissions/constant.MANAGE_CHANNELS.html
- #[inline]
- pub fn delete_permission(&self, permission_type: PermissionOverwriteType) -> Result<()> {
- self.id.delete_permission(permission_type)
- }
-
- /// Deletes this category.
- #[inline]
- pub fn delete(&self) -> Result<()> {
- #[cfg(feature = "cache")]
- {
- let req = Permissions::MANAGE_CHANNELS;
-
- if !utils::user_has_perms(self.id, req)? {
- return Err(Error::Model(ModelError::InvalidPermissions(req)));
- }
- }
-
- self.id.delete().map(|_| ())
- }
-
- /// Modifies the category's settings, such as its position or name.
- ///
- /// Refer to `EditChannel`s documentation for a full list of methods.
- ///
- /// # Examples
- ///
- /// Change a voice channels name and bitrate:
- ///
- /// ```rust,ignore
- /// category.edit(|c| c.name("test").bitrate(86400));
- /// ```
- #[cfg(all(feature = "builder", feature = "model", feature = "utils"))]
- pub fn edit<F>(&mut self, f: F) -> Result<()>
- where F: FnOnce(EditChannel) -> EditChannel {
- #[cfg(feature = "cache")]
- {
- let req = Permissions::MANAGE_CHANNELS;
-
- if !utils::user_has_perms(self.id, req)? {
- return Err(Error::Model(ModelError::InvalidPermissions(req)));
- }
- }
-
- let mut map = VecMap::new();
- map.insert("name", Value::String(self.name.clone()));
- map.insert("position", Value::Number(Number::from(self.position)));
- map.insert("type", Value::String(self.kind.name().to_string()));
-
- let map = serenity_utils::vecmap_to_json_map(f(EditChannel(map)).0);
-
- http::edit_channel(self.id.0, &map).map(|channel| {
- let GuildChannel {
- id,
- category_id,
- permission_overwrites,
- nsfw,
- name,
- position,
- kind,
- ..
- } = channel;
-
- *self = ChannelCategory {
- id,
- category_id,
- permission_overwrites,
- nsfw,
- name,
- position,
- kind,
- };
- ()
- })
- }
-
#[cfg(feature = "utils")]
#[inline]
pub fn is_nsfw(&self) -> bool {
diff --git a/src/model/channel/channel_id.rs b/src/model/channel/channel_id.rs
index f4336fc..fc6d748 100644
--- a/src/model/channel/channel_id.rs
+++ b/src/model/channel/channel_id.rs
@@ -1,577 +1,13 @@
-use internal::RwLockExt;
use model::prelude::*;
-#[cfg(feature = "model")]
-use std::borrow::Cow;
-#[cfg(feature = "model")]
-use std::fmt::Write as FmtWrite;
-#[cfg(feature = "model")]
-use builder::{
- CreateMessage,
- EditChannel,
- EditMessage,
- GetMessages
-};
-#[cfg(all(feature = "cache", feature = "model"))]
-use CACHE;
-#[cfg(feature = "model")]
-use http::{self, AttachmentType};
-#[cfg(feature = "model")]
-use utils;
-
-#[cfg(feature = "model")]
-impl ChannelId {
- /// 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<()> { http::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 = json!({
- "allow": target.allow.bits(),
- "deny": target.deny.bits(),
- "id": id,
- "type": kind,
- });
-
- http::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> {
- http::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> { http::delete_channel(self.0) }
-
- /// Deletes a [`Message`] given its Id.
- ///
- /// Refer to [`Message::delete`] for more information.
- ///
- /// Requires the [Manage Messages] permission, if the current user is not
- /// the author of the message.
- ///
- /// [`Message`]: struct.Message.html
- /// [`Message::delete`]: struct.Message.html#method.delete
- /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
- #[inline]
- pub fn delete_message<M: Into<MessageId>>(&self, message_id: M) -> Result<()> {
- http::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**: Messages that are older than 2 weeks can't be deleted using
- /// this method.
- ///
- /// # Errors
- ///
- /// Returns [`ModelError::BulkDeleteAmount`] if an attempt was made to
- /// delete either 0 or more than 100 messages.
- ///
- /// [`Channel::delete_messages`]: enum.Channel.html#method.delete_messages
- /// [`ModelError::BulkDeleteAmount`]: ../enum.ModelError.html#variant.BulkDeleteAmount
- /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
- pub fn delete_messages<T: AsRef<MessageId>, It: IntoIterator<Item=T>>(&self, message_ids: It) -> Result<()> {
- let ids = message_ids
- .into_iter()
- .map(|message_id| message_id.as_ref().0)
- .collect::<Vec<u64>>();
- let len = ids.len();
-
- if len == 0 || len > 100 {
- return Err(Error::Model(ModelError::BulkDeleteAmount));
- } else if ids.len() == 1 {
- self.delete_message(ids[0])
- } else {
- let map = json!({ "messages": ids });
-
- http::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<()> {
- http::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> {
- http::delete_reaction(
- self.0,
- message_id.into().0,
- user_id.map(|uid| uid.0),
- &reaction_type.into(),
- )
- }
-
-
- /// Edits the settings of a [`Channel`], optionally setting new values.
- ///
- /// Refer to `EditChannel`'s documentation for its methods.
- ///
- /// Requires the [Manage Channel] permission.
- ///
- /// # Examples
- ///
- /// Change a voice channel's name and bitrate:
- ///
- /// ```rust,ignore
- /// // assuming a `channel_id` has been bound
- ///
- /// channel_id.edit(|c| c.name("test").bitrate(64000));
- /// ```
- ///
- /// [`Channel`]: enum.Channel.html
- /// [Manage Channel]: permissions/constant.MANAGE_CHANNELS.html
- #[cfg(feature = "utils")]
- #[inline]
- pub fn edit<F: FnOnce(EditChannel) -> EditChannel>(&self, f: F) -> Result<GuildChannel> {
- let map = utils::vecmap_to_json_map(f(EditChannel::default()).0);
-
- http::edit_channel(self.0, &map)
- }
-
- /// Edits a [`Message`] in the channel given its Id.
- ///
- /// Message editing preserves all unchanged message data.
- ///
- /// Refer to the documentation for [`EditMessage`] for more information
- /// regarding message restrictions and requirements.
- ///
- /// **Note**: Requires that the current user be the author of the message.
- ///
- /// # Errors
- ///
- /// Returns a [`ModelError::MessageTooLong`] if the content of the message
- /// is over the [`the limit`], containing the number of unicode code points
- /// over the limit.
- ///
- /// [`ModelError::MessageTooLong`]: enum.ModelError.html#variant.MessageTooLong
- /// [`EditMessage`]: ../builder/struct.EditMessage.html
- /// [`Message`]: struct.Message.html
- /// [`the limit`]: ../builder/struct.EditMessage.html#method.content
- #[cfg(feature = "utils")]
- pub fn edit_message<F, M>(&self, message_id: M, f: F) -> Result<Message>
- where F: FnOnce(EditMessage) -> EditMessage, M: Into<MessageId> {
- let msg = f(EditMessage::default());
-
- if let Some(content) = msg.0.get(&"content") {
- if let Value::String(ref content) = *content {
- if let Some(length_over) = Message::overflow_length(content) {
- return Err(Error::Model(ModelError::MessageTooLong(length_over)));
- }
- }
- }
-
- let map = utils::vecmap_to_json_map(msg.0);
-
- http::edit_message(self.0, message_id.into().0, &Value::Object(map))
- }
-
- /// Search the cache for the channel with the Id.
- #[cfg(feature = "cache")]
- pub fn find(&self) -> Option<Channel> { CACHE.read().channel(*self) }
-
- /// Search the cache for the channel. If it can't be found, the channel is
- /// requested over REST.
- pub fn get(&self) -> Result<Channel> {
- #[cfg(feature = "cache")]
- {
- if let Some(channel) = CACHE.read().channel(*self) {
- return Ok(channel);
- }
- }
-
- http::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 invites(&self) -> Result<Vec<RichInvite>> { http::get_channel_invites(self.0) }
-
- /// Gets a message from the channel.
- ///
- /// Requires the [Read Message History] permission.
- ///
- /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
- #[inline]
- pub fn message<M: Into<MessageId>>(&self, message_id: M) -> Result<Message> {
- http::get_message(self.0, message_id.into().0)
- .map(|mut msg| {
- msg.transform_content();
-
- msg
- })
- }
-
- /// Gets messages from the channel.
- ///
- /// Refer to [`Channel::messages`] for more information.
- ///
- /// Requires the [Read Message History] permission.
- ///
- /// [`Channel::messages`]: enum.Channel.html#method.messages
- /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
- pub fn 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)?;
- }
-
- http::get_messages(self.0, &query).map(|msgs| {
- msgs.into_iter()
- .map(|mut msg| {
- msg.transform_content();
-
- msg
- })
- .collect::<Vec<Message>>()
- })
- }
-
- /// Returns the name of whatever channel this id holds.
- #[cfg(feature = "model")]
- pub fn name(&self) -> Option<String> {
- use self::Channel::*;
-
- let finding = feature_cache! {{
- Some(self.find())
- } else {
- None
- }};
-
- let channel = if let Some(Some(c)) = finding {
- c
- } else {
- return None;
- };
-
- Some(match channel {
- Guild(channel) => channel.read().name().to_string(),
- Group(channel) => match channel.read().name() {
- Cow::Borrowed(name) => name.to_string(),
- Cow::Owned(name) => name,
- },
- Category(category) => category.read().name().to_string(),
- Private(channel) => channel.read().name(),
- })
- }
-
- /// Pins a [`Message`] to the channel.
- ///
- /// [`Message`]: struct.Message.html
- #[inline]
- pub fn pin<M: Into<MessageId>>(&self, message_id: M) -> Result<()> {
- http::pin_message(self.0, message_id.into().0)
- }
-
- /// Gets the list of [`Message`]s which are pinned to the channel.
- ///
- /// [`Message`]: struct.Message.html
- #[inline]
- pub fn pins(&self) -> Result<Vec<Message>> { http::get_pins(self.0) }
-
- /// Gets the list of [`User`]s who have reacted to a [`Message`] with a
- /// certain [`Emoji`].
- ///
- /// Refer to [`Channel::reaction_users`] for more information.
- ///
- /// **Note**: Requires the [Read Message History] permission.
- ///
- /// [`Channel::reaction_users`]: enum.Channel.html#method.reaction_users
- /// [`Emoji`]: struct.Emoji.html
- /// [`Message`]: struct.Message.html
- /// [`User`]: struct.User.html
- /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
- pub fn reaction_users<M, R, U>(&self,
- message_id: M,
- reaction_type: R,
- limit: Option<u8>,
- after: U,
- ) -> Result<Vec<User>> where M: Into<MessageId>,
- R: Into<ReactionType>,
- U: Into<Option<UserId>> {
- let limit = limit.map_or(50, |x| if x > 100 { 100 } else { x });
-
- http::get_reaction_users(
- self.0,
- message_id.into().0,
- &reaction_type.into(),
- limit,
- after.into().map(|x| x.0),
- )
- }
-
- /// Sends a message with just the given message content in the channel.
- ///
- /// # Errors
- ///
- /// Returns a [`ModelError::MessageTooLong`] if the content of the message
- /// is over the above limit, containing the number of unicode code points
- /// over the limit.
- ///
- /// [`ChannelId`]: struct.ChannelId.html
- /// [`ModelError::MessageTooLong`]: enum.ModelError.html#variant.MessageTooLong
- #[inline]
- pub fn say<D: ::std::fmt::Display>(&self, content: D) -> Result<Message> {
- self.send_message(|mut m| {
- m.content(content);
-
- m
- })
- }
-
- /// Sends a file along with optional message contents. The filename _must_
- /// be specified.
- ///
- /// Message contents may be passed by using the [`CreateMessage::content`]
- /// method.
- ///
- /// The [Attach Files] and [Send Messages] permissions are required.
- ///
- /// **Note**: Message contents must be under 2000 unicode code points.
- ///
- /// # Examples
- ///
- /// Send files with the paths `/path/to/file.jpg` and `/path/to/file2.jpg`:
- ///
- /// ```rust,no_run
- /// use serenity::model::id::ChannelId;
- ///
- /// let channel_id = ChannelId(7);
- ///
- /// let paths = vec!["/path/to/file.jpg", "path/to/file2.jpg"];
- ///
- /// let _ = channel_id.send_files(paths, |mut m| {
- /// m.content("a file");
- ///
- /// m
- /// });
- /// ```
- ///
- /// Send files using `File`:
- ///
- /// ```rust,no_run
- /// use serenity::model::id::ChannelId;
- /// use std::fs::File;
- ///
- /// let channel_id = ChannelId(7);
- ///
- /// let f1 = File::open("my_file.jpg").unwrap();
- /// let f2 = File::open("my_file2.jpg").unwrap();
- ///
- /// let files = vec![(&f1, "my_file.jpg"), (&f2, "my_file2.jpg")];
- ///
- /// let _ = channel_id.send_files(files, |mut m| {
- /// m.content("a file");
- ///
- /// m
- /// });
- /// ```
- ///
- /// # 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.
- ///
- /// Returns an
- /// [`HttpError::InvalidRequest(PayloadTooLarge)`][`HttpError::InvalidRequest`]
- /// if the file is too large to send.
- ///
- /// [`ClientError::MessageTooLong`]: ../client/enum.ClientError.html#variant.MessageTooLong
- /// [`HttpError::InvalidRequest`]: ../http/enum.HttpError.html#variant.InvalidRequest
- /// [`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
- #[cfg(feature = "utils")]
- pub fn send_files<'a, F, T, It: IntoIterator<Item=T>>(&self, files: It, f: F) -> Result<Message>
- where F: FnOnce(CreateMessage) -> CreateMessage, T: Into<AttachmentType<'a>> {
- let mut msg = f(CreateMessage::default());
-
- if let Some(content) = msg.0.get(&"content") {
- if let Value::String(ref content) = *content {
- if let Some(length_over) = Message::overflow_length(content) {
- return Err(Error::Model(ModelError::MessageTooLong(length_over)));
- }
- }
- }
-
- if let Some(e) = msg.0.remove(&"embed") {
- msg.0.insert("payload_json", json!({ "embed": e }));
- }
-
- let map = utils::vecmap_to_json_map(msg.0);
- http::send_files(self.0, files, map)
- }
-
- /// Sends a message to the channel.
- ///
- /// Refer to the documentation for [`CreateMessage`] for more information
- /// regarding message restrictions and requirements.
- ///
- /// Requires the [Send Messages] permission.
- ///
- /// **Note**: Message contents must be under 2000 unicode code points.
- ///
- /// # Errors
- ///
- /// Returns a [`ModelError::MessageTooLong`] if the content of the message
- /// is over the above limit, containing the number of unicode code points
- /// over the limit.
- ///
- /// [`Channel`]: enum.Channel.html
- /// [`ModelError::MessageTooLong`]: enum.ModelError.html#variant.MessageTooLong
- /// [`CreateMessage`]: ../builder/struct.CreateMessage.html
- /// [Send Messages]: permissions/constant.SEND_MESSAGES.html
- #[cfg(feature = "utils")]
- pub fn send_message<F>(&self, f: F) -> Result<Message>
- where F: FnOnce(CreateMessage) -> CreateMessage {
- let mut msg = f(CreateMessage::default());
-
- if !msg.2.is_empty() {
- if let Some(e) = msg.0.remove(&"embed") {
- msg.0.insert("payload_json", json!({ "embed": e }));
- }
- }
-
- let map = utils::vecmap_to_json_map(msg.0);
-
- Message::check_content_length(&map)?;
- Message::check_embed_length(&map)?;
-
- let message = if msg.2.is_empty() {
- http::send_message(self.0, &Value::Object(map))?
- } else {
- http::send_files(self.0, msg.2, map)?
- };
-
- if let Some(reactions) = msg.1 {
- for reaction in reactions {
- self.create_reaction(message.id, reaction)?;
- }
- }
-
- Ok(message)
- }
-
- /// 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<()> {
- http::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>> { http::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.with(|g| g.channel_id),
- Channel::Guild(ch) => ch.with(|c| c.id),
- Channel::Private(ch) => ch.with(|c| c.id),
- Channel::Category(ch) => ch.with(|c| c.id),
+ Channel::Group(group) => group.borrow().channel_id,
+ Channel::Guild(ch) => ch.borrow().id,
+ Channel::Private(ch) => ch.borrow().id,
+ Channel::Category(ch) => ch.borrow().id,
}
}
}
@@ -580,10 +16,10 @@ impl<'a> From<&'a Channel> for ChannelId {
/// Gets the Id of a `Channel`.
fn from(channel: &Channel) -> ChannelId {
match *channel {
- Channel::Group(ref group) => group.with(|g| g.channel_id),
- Channel::Guild(ref ch) => ch.with(|c| c.id),
- Channel::Private(ref ch) => ch.with(|c| c.id),
- Channel::Category(ref ch) => ch.with(|c| c.id),
+ Channel::Group(ref group) => group.borrow().channel_id,
+ Channel::Guild(ref ch) => ch.borrow().id,
+ Channel::Private(ref ch) => ch.borrow().id,
+ Channel::Category(ref ch) => ch.borrow().id,
}
}
}
diff --git a/src/model/channel/embed.rs b/src/model/channel/embed.rs
index 8792d18..4baf622 100644
--- a/src/model/channel/embed.rs
+++ b/src/model/channel/embed.rs
@@ -1,11 +1,9 @@
-#[cfg(feature = "model")]
use builder::CreateEmbed;
-#[cfg(feature = "model")]
use internal::prelude::*;
+use utils;
+
#[cfg(feature = "utils")]
use utils::Colour;
-#[cfg(feature = "model")]
-use utils;
/// Represents a rich embed which allows using richer markdown, multiple fields
/// and more. This was heavily inspired by [slack's attachments].
@@ -65,7 +63,6 @@ pub struct Embed {
pub video: Option<EmbedVideo>,
}
-#[cfg(feature = "model")]
impl Embed {
/// Creates a fake Embed, giving back a `serde_json` map.
///
diff --git a/src/model/channel/group.rs b/src/model/channel/group.rs
index 2fc062b..db15e8f 100644
--- a/src/model/channel/group.rs
+++ b/src/model/channel/group.rs
@@ -1,20 +1,9 @@
use chrono::{DateTime, FixedOffset};
use model::prelude::*;
-
-#[cfg(feature = "model")]
-use builder::{
- CreateMessage,
- EditMessage,
- GetMessages
-};
-#[cfg(feature = "model")]
-use http::{self, AttachmentType};
-#[cfg(feature = "model")]
-use internal::RwLockExt;
-#[cfg(feature = "model")]
use std::borrow::Cow;
-#[cfg(feature = "model")]
+use std::cell::RefCell;
use std::fmt::Write as FmtWrite;
+use std::rc::Rc;
/// A group channel - potentially including other [`User`]s - separate from a
/// [`Guild`].
@@ -39,129 +28,10 @@ pub struct Group {
/// A map of the group's recipients.
#[serde(deserialize_with = "deserialize_users",
serialize_with = "serialize_users")]
- pub recipients: HashMap<UserId, Arc<RwLock<User>>>,
+ pub recipients: HashMap<UserId, Rc<RefCell<User>>>,
}
-#[cfg(feature = "model")]
impl Group {
- /// Adds the given user to the group. If the user is already in the group,
- /// then nothing is done.
- ///
- /// Refer to [`http::add_group_recipient`] for more information.
- ///
- /// **Note**: Groups have a limit of 10 recipients, including the current
- /// user.
- ///
- /// [`http::add_group_recipient`]: ../http/fn.add_group_recipient.html
- pub fn add_recipient<U: Into<UserId>>(&self, user: U) -> Result<()> {
- let user = user.into();
-
- // If the group already contains the recipient, do nothing.
- if self.recipients.contains_key(&user) {
- return Ok(());
- }
-
- http::add_group_recipient(self.channel_id.0, user.0)
- }
-
- /// Broadcasts that the current user is typing in the group.
- #[inline]
- pub fn broadcast_typing(&self) -> Result<()> { self.channel_id.broadcast_typing() }
-
- /// React to a [`Message`] with a custom [`Emoji`] or unicode character.
- ///
- /// [`Message::react`] may be a more suited method of reacting in most
- /// cases.
- ///
- /// Requires the [Add Reactions] permission, _if_ the current user is the
- /// first user to perform a react with a certain emoji.
- ///
- /// [`Emoji`]: struct.Emoji.html
- /// [`Message`]: struct.Message.html
- /// [`Message::react`]: struct.Message.html#method.react
- /// [Add Reactions]: permissions/constant.ADD_REACTIONS.html
- #[inline]
- pub fn create_reaction<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.
- ///
- /// Refer to [`Channel::delete_messages`] for more information.
- ///
- /// Requires the [Manage Messages] permission.
- ///
- /// **Note**: Messages that are older than 2 weeks can't be deleted using
- /// this method.
- ///
- /// # Errors
- ///
- /// Returns [`ModelError::BulkDeleteAmount`] if an attempt was made to
- /// delete either 0 or more than 100 messages.
- ///
- /// [`Channel::delete_messages`]: enum.Channel.html#method.delete_messages
- /// [`ModelError::BulkDeleteAmount`]: ../enum.ModelError.html#variant.BulkDeleteAmount
- /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
- #[inline]
- pub fn delete_messages<T: AsRef<MessageId>, It: IntoIterator<Item=T>>(&self, message_ids: It) -> Result<()> {
- self.channel_id.delete_messages(message_ids)
- }
-
- /// Deletes all permission overrides in the channel from a member
- /// or role.
- ///
- /// **Note**: Requires the [Manage Channel] permission.
- ///
- /// [Manage Channel]: permissions/constant.MANAGE_CHANNELS.html
- #[inline]
- pub fn delete_permission(&self, permission_type: PermissionOverwriteType) -> Result<()> {
- self.channel_id.delete_permission(permission_type)
- }
-
- /// Deletes the given [`Reaction`] from the channel.
- ///
- /// **Note**: Requires the [Manage Messages] permission, _if_ the current
- /// user did not perform the reaction.
- ///
- /// [`Reaction`]: struct.Reaction.html
- /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
- #[inline]
- pub fn delete_reaction<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)
- }
-
- /// Edits a [`Message`] in the channel given its Id.
- ///
- /// Message editing preserves all unchanged message data.
- ///
- /// Refer to the documentation for [`EditMessage`] for more information
- /// regarding message restrictions and requirements.
- ///
- /// **Note**: Requires that the current user be the author of the message.
- ///
- /// # Errors
- ///
- /// Returns a [`ModelError::MessageTooLong`] if the content of the message
- /// is over the [`the limit`], containing the number of unicode code points
- /// over the limit.
- ///
- /// [`ModelError::MessageTooLong`]: enum.ModelError.html#variant.MessageTooLong
- /// [`EditMessage`]: ../builder/struct.EditMessage.html
- /// [`Message`]: struct.Message.html
- /// [`the limit`]: ../builder/struct.EditMessage.html#method.content
- #[inline]
- pub fn edit_message<F, M>(&self, message_id: M, f: F) -> Result<Message>
- where F: FnOnce(EditMessage) -> EditMessage, M: Into<MessageId> {
- self.channel_id.edit_message(message_id, f)
- }
-
/// Returns the formatted URI of the group's icon if one exists.
pub fn icon_url(&self) -> Option<String> {
self.icon.as_ref().map(|icon| {
@@ -180,31 +50,6 @@ impl Group {
#[inline]
pub fn is_nsfw(&self) -> bool { false }
- /// Leaves the group.
- #[inline]
- pub fn leave(&self) -> Result<Group> { http::leave_group(self.channel_id.0) }
-
- /// Gets a message from the channel.
- ///
- /// Requires the [Read Message History] permission.
- ///
- /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
- #[inline]
- pub fn message<M: Into<MessageId>>(&self, message_id: M) -> Result<Message> {
- self.channel_id.message(message_id)
- }
-
- /// Gets messages from the channel.
- ///
- /// Requires the [Read Message History] permission.
- ///
- /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
- #[inline]
- pub fn messages<F>(&self, f: F) -> Result<Vec<Message>>
- where F: FnOnce(GetMessages) -> GetMessages {
- self.channel_id.messages(f)
- }
-
/// Generates a name for the group.
///
/// If there are no recipients in the group, the name will be "Empty Group".
@@ -215,122 +60,18 @@ impl Group {
Some(ref name) => Cow::Borrowed(name),
None => {
let mut name = match self.recipients.values().nth(0) {
- Some(recipient) => recipient.with(|c| c.name.clone()),
+ Some(recipient) => recipient.borrow().name.clone(),
None => return Cow::Borrowed("Empty Group"),
};
for recipient in self.recipients.values().skip(1) {
- let _ = write!(name, ", {}", recipient.with(|r| r.name.clone()));
+ let recipient = recipient.borrow();
+
+ let _ = write!(name, ", {}", recipient.name);
}
Cow::Owned(name)
},
}
}
-
- /// Retrieves the list of messages that have been pinned in the group.
- #[inline]
- pub fn pins(&self) -> Result<Vec<Message>> { self.channel_id.pins() }
-
- /// Gets the list of [`User`]s who have reacted to a [`Message`] with a
- /// certain [`Emoji`].
- ///
- /// Refer to [`Channel::reaction_users`] for more information.
- ///
- /// **Note**: Requires the [Read Message History] permission.
- ///
- /// [`Channel::reaction_users`]: enum.Channel.html#method.reaction_users
- /// [`Emoji`]: struct.Emoji.html
- /// [`Message`]: struct.Message.html
- /// [`User`]: struct.User.html
- /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
- #[inline]
- pub fn reaction_users<M, R, U>(
- &self,
- message_id: M,
- reaction_type: R,
- limit: Option<u8>,
- after: U,
- ) -> Result<Vec<User>> where M: Into<MessageId>,
- R: Into<ReactionType>,
- U: Into<Option<UserId>> {
- self.channel_id.reaction_users(message_id, reaction_type, limit, after)
- }
-
- /// Removes a recipient from the group. If the recipient is already not in
- /// the group, then nothing is done.
- ///
- /// **Note**: This is only available to the group owner.
- pub fn remove_recipient<U: Into<UserId>>(&self, user: U) -> Result<()> {
- let user = user.into();
-
- // If the group does not contain the recipient already, do nothing.
- if !self.recipients.contains_key(&user) {
- return Ok(());
- }
-
- http::remove_group_recipient(self.channel_id.0, user.0)
- }
-
- /// Sends a message with just the given message content in the channel.
- ///
- /// # Errors
- ///
- /// Returns a [`ModelError::MessageTooLong`] if the content of the message
- /// is over the above limit, containing the number of unicode code points
- /// over the limit.
- ///
- /// [`ChannelId`]: ../model/id/struct.ChannelId.html
- /// [`ModelError::MessageTooLong`]: enum.ModelError.html#variant.MessageTooLong
- #[inline]
- pub fn say(&self, content: &str) -> Result<Message> { self.channel_id.say(content) }
-
- /// Sends (a) file(s) along with optional message contents.
- ///
- /// Refer to [`ChannelId::send_files`] for examples and more information.
- ///
- /// The [Attach Files] and [Send Messages] permissions are required.
- ///
- /// **Note**: Message contents must be under 2000 unicode code points.
- ///
- /// # Errors
- ///
- /// If the content of the message is over the above limit, then a
- /// [`ClientError::MessageTooLong`] will be returned, containing the number
- /// of unicode code points over the limit.
- ///
- /// [`ChannelId::send_files`]: struct.ChannelId.html#method.send_files
- /// [`ClientError::MessageTooLong`]: ../client/enum.ClientError.html#variant.MessageTooLong
- /// [Attach Files]: permissions/constant.ATTACH_FILES.html
- /// [Send Messages]: permissions/constant.SEND_MESSAGES.html
- #[inline]
- pub fn send_files<'a, F, T, It: IntoIterator<Item=T>>(&self, files: It, f: F) -> Result<Message>
- where F: FnOnce(CreateMessage) -> CreateMessage, T: Into<AttachmentType<'a>> {
- self.channel_id.send_files(files, f)
- }
-
- /// Sends a message to the group with the given content.
- ///
- /// Refer to the documentation for [`CreateMessage`] for more information
- /// regarding message restrictions and requirements.
- ///
- /// **Note**: Requires the [Send Messages] permission.
- ///
- /// [`CreateMessage`]: ../builder/struct.CreateMessage.html
- /// [Send Messages]: permissions/constant.SEND_MESSAGES.html
- #[inline]
- pub fn send_message<F: FnOnce(CreateMessage) -> CreateMessage>(&self, f: F) -> Result<Message> {
- self.channel_id.send_message(f)
- }
-
- /// Unpins a [`Message`] in the channel given by its Id.
- ///
- /// Requires the [Manage Messages] permission.
- ///
- /// [`Message`]: struct.Message.html
- /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
- #[inline]
- pub fn unpin<M: Into<MessageId>>(&self, message_id: M) -> Result<()> {
- self.channel_id.unpin(message_id)
- }
}
diff --git a/src/model/channel/guild_channel.rs b/src/model/channel/guild_channel.rs
index c6d9031..3c976d1 100644
--- a/src/model/channel/guild_channel.rs
+++ b/src/model/channel/guild_channel.rs
@@ -1,30 +1,9 @@
use chrono::{DateTime, FixedOffset};
use model::prelude::*;
-#[cfg(all(feature = "cache", feature = "model"))]
-use CACHE;
-#[cfg(feature = "model")]
-use builder::{
- CreateInvite,
- CreateMessage,
- EditChannel,
- EditMessage,
- GetMessages
-};
-#[cfg(feature = "model")]
-use http::{self, AttachmentType};
-#[cfg(all(feature = "cache", feature = "model"))]
-use internal::prelude::*;
-#[cfg(feature = "model")]
-use std::fmt::{
- Display,
- Formatter,
- Result as FmtResult
-};
-#[cfg(feature = "model")]
-use std::mem;
-#[cfg(all(feature = "model", feature = "utils"))]
-use utils::{self as serenity_utils, VecMap};
+use std::fmt::{Display, Formatter, Result as FmtResult};
+#[cfg(feature = "utils")]
+use utils as serenity_utils;
/// Represents a guild's text or voice channel. Some methods are available only
/// for voice channels and some are only available for text channels.
@@ -89,300 +68,7 @@ pub struct GuildChannel {
pub nsfw: bool,
}
-#[cfg(feature = "model")]
impl GuildChannel {
- /// Broadcasts to the channel that the current user is typing.
- ///
- /// For bots, this is a good indicator for long-running commands.
- ///
- /// **Note**: Requires the [Send Messages] permission.
- ///
- /// # Errors
- ///
- /// Returns a [`ModelError::InvalidPermissions`] if the current user does
- /// not have the required permissions.
- ///
- /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
- /// [Send Messages]: permissions/constant.SEND_MESSAGES.html
- pub fn broadcast_typing(&self) -> Result<()> { self.id.broadcast_typing() }
-
- /// Creates an invite leading to the given channel.
- ///
- /// # Examples
- ///
- /// Create an invite that can only be used 5 times:
- ///
- /// ```rust,ignore
- /// let invite = channel.create_invite(|i| i.max_uses(5));
- /// ```
- #[cfg(feature = "utils")]
- pub fn create_invite<F>(&self, f: F) -> Result<RichInvite>
- where F: FnOnce(CreateInvite) -> CreateInvite {
- #[cfg(feature = "cache")]
- {
- let req = Permissions::CREATE_INVITE;
-
- if !utils::user_has_perms(self.id, req)? {
- return Err(Error::Model(ModelError::InvalidPermissions(req)));
- }
- }
-
- let map = serenity_utils::vecmap_to_json_map(f(CreateInvite::default()).0);
-
- http::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,no_run
- /// # use serenity::model::id::{ChannelId, UserId};
- /// # use std::error::Error;
- /// #
- /// # fn try_main() -> Result<(), Box<Error>> {
- /// # let (channel_id, user_id) = (ChannelId(0), UserId(0));
- /// #
- /// use serenity::model::channel::{
- /// PermissionOverwrite,
- /// PermissionOverwriteType,
- /// };
- /// use serenity::model::{ModelError, Permissions};
- /// use serenity::CACHE;
- ///
- /// let allow = Permissions::SEND_MESSAGES;
- /// let deny = Permissions::SEND_TTS_MESSAGES | Permissions::ATTACH_FILES;
- /// let overwrite = PermissionOverwrite {
- /// allow: allow,
- /// deny: deny,
- /// kind: PermissionOverwriteType::Member(user_id),
- /// };
- ///
- /// let cache = CACHE.read();
- /// let channel = cache
- /// .guild_channel(channel_id)
- /// .ok_or(ModelError::ItemMissing)?;
- ///
- /// channel.read().create_permission(&overwrite)?;
- /// # Ok(())
- /// # }
- /// #
- /// # fn main() {
- /// # try_main().unwrap();
- /// # }
- /// ```
- ///
- /// Creating a permission overwrite for a role by specifying the
- /// [`PermissionOverwrite::Role`] variant, allowing it the [Manage Webhooks]
- /// permission, but denying the [Send TTS Messages] and [Attach Files]
- /// permissions:
- ///
- /// ```rust,no_run
- /// # use serenity::model::id::{ChannelId, UserId};
- /// # use std::error::Error;
- /// #
- /// # fn try_main() -> Result<(), Box<Error>> {
- /// # let (channel_id, user_id) = (ChannelId(0), UserId(0));
- /// #
- /// use serenity::model::channel::{
- /// PermissionOverwrite,
- /// PermissionOverwriteType,
- /// };
- /// use serenity::model::{ModelError, Permissions};
- /// use serenity::CACHE;
- ///
- /// let allow = Permissions::SEND_MESSAGES;
- /// let deny = Permissions::SEND_TTS_MESSAGES | Permissions::ATTACH_FILES;
- /// let overwrite = PermissionOverwrite {
- /// allow: allow,
- /// deny: deny,
- /// kind: PermissionOverwriteType::Member(user_id),
- /// };
- ///
- /// let cache = CACHE.read();
- /// let channel = cache
- /// .guild_channel(channel_id)
- /// .ok_or(ModelError::ItemMissing)?;
- ///
- /// channel.read().create_permission(&overwrite)?;
- /// # Ok(())
- /// # }
- /// #
- /// # fn main() {
- /// # try_main().unwrap();
- /// # }
- /// ```
- ///
- /// [`Channel`]: enum.Channel.html
- /// [`Member`]: struct.Member.html
- /// [`PermissionOverwrite`]: struct.PermissionOverwrite.html
- /// [`PermissionOverwrite::Member`]: struct.PermissionOverwrite.html#variant.Member
- /// [`PermissionOverwrite::Role`]: struct.PermissionOverwrite.html#variant.Role
- /// [`Role`]: struct.Role.html
- /// [Attach Files]: permissions/constant.ATTACH_FILES.html
- /// [Manage Channels]: permissions/constant.MANAGE_CHANNELS.html
- /// [Manage Webhooks]: permissions/constant.MANAGE_WEBHOOKS.html
- /// [Send Messages]: permissions/constant.SEND_MESSAGES.html
- /// [Send TTS Messages]: permissions/constant.SEND_TTS_MESSAGES.html
- #[inline]
- pub fn create_permission(&self, target: &PermissionOverwrite) -> Result<()> {
- self.id.create_permission(target)
- }
-
- /// Deletes this channel, returning the channel on a successful deletion.
- pub fn delete(&self) -> Result<Channel> {
- #[cfg(feature = "cache")]
- {
- let req = Permissions::MANAGE_CHANNELS;
-
- if !utils::user_has_perms(self.id, req)? {
- return Err(Error::Model(ModelError::InvalidPermissions(req)));
- }
- }
-
- 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**: Messages that are older than 2 weeks can't be deleted using
- /// this method.
- ///
- /// # Errors
- ///
- /// Returns [`ModelError::BulkDeleteAmount`] if an attempt was made to
- /// delete either 0 or more than 100 messages.
- ///
- /// [`Channel::delete_messages`]: enum.Channel.html#method.delete_messages
- /// [`ModelError::BulkDeleteAmount`]: ../enum.ModelError.html#variant.BulkDeleteAmount
- /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
- #[inline]
- pub fn delete_messages<T: AsRef<MessageId>, It: IntoIterator<Item=T>>(&self, message_ids: It) -> 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.
- ///
- /// Refer to `EditChannel`s documentation for a full list of methods.
- ///
- /// # Examples
- ///
- /// Change a voice channels name and bitrate:
- ///
- /// ```rust,ignore
- /// channel.edit(|c| c.name("test").bitrate(86400));
- /// ```
- #[cfg(feature = "utils")]
- pub fn edit<F>(&mut self, f: F) -> Result<()>
- where F: FnOnce(EditChannel) -> EditChannel {
- #[cfg(feature = "cache")]
- {
- let req = Permissions::MANAGE_CHANNELS;
-
- if !utils::user_has_perms(self.id, req)? {
- return Err(Error::Model(ModelError::InvalidPermissions(req)));
- }
- }
-
- let mut map = VecMap::new();
- map.insert("name", Value::String(self.name.clone()));
- map.insert("position", Value::Number(Number::from(self.position)));
- map.insert("type", Value::String(self.kind.name().to_string()));
-
- let edited = serenity_utils::vecmap_to_json_map(f(EditChannel(map)).0);
-
- match http::edit_channel(self.id.0, &edited) {
- Ok(channel) => {
- mem::replace(self, channel);
-
- Ok(())
- },
- Err(why) => Err(why),
- }
- }
-
- /// Edits a [`Message`] in the channel given its Id.
- ///
- /// Message editing preserves all unchanged message data.
- ///
- /// Refer to the documentation for [`EditMessage`] for more information
- /// regarding message restrictions and requirements.
- ///
- /// **Note**: Requires that the current user be the author of the message.
- ///
- /// # Errors
- ///
- /// Returns a [`ModelError::MessageTooLong`] if the content of the message
- /// is over the [`the limit`], containing the number of unicode code points
- /// over the limit.
- ///
- /// [`ModelError::MessageTooLong`]: enum.ModelError.html#variant.MessageTooLong
- /// [`EditMessage`]: ../builder/struct.EditMessage.html
- /// [`Message`]: struct.Message.html
- /// [`the limit`]: ../builder/struct.EditMessage.html#method.content
- #[inline]
- pub fn edit_message<F, M>(&self, message_id: M, f: F) -> Result<Message>
- where F: FnOnce(EditMessage) -> EditMessage, M: Into<MessageId> {
- self.id.edit_message(message_id, f)
- }
-
- /// Attempts to find this channel's guild in the Cache.
- ///
- /// **Note**: Right now this performs a clone of the guild. This will be
- /// optimized in the future.
- #[cfg(feature = "cache")]
- pub fn guild(&self) -> Option<Arc<RwLock<Guild>>> { CACHE.read().guild(self.guild_id) }
-
- /// Gets all of the channel's invites.
- ///
- /// Requires the [Manage Channels] permission.
- /// [Manage Channels]: permissions/constant.MANAGE_CHANNELS.html
- #[inline]
- pub fn invites(&self) -> Result<Vec<RichInvite>> { self.id.invites() }
-
/// Determines if the channel is NSFW.
///
/// Refer to [`utils::is_nsfw`] for more details.
@@ -399,258 +85,10 @@ impl GuildChannel {
self.kind == ChannelType::Text && (self.nsfw || serenity_utils::is_nsfw(&self.name))
}
- /// Gets a message from the channel.
- ///
- /// Requires the [Read Message History] permission.
- ///
- /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
- #[inline]
- pub fn message<M: Into<MessageId>>(&self, message_id: M) -> Result<Message> {
- self.id.message(message_id)
- }
-
- /// Gets messages from the channel.
- ///
- /// Refer to [`Channel::messages`] for more information.
- ///
- /// Requires the [Read Message History] permission.
- ///
- /// [`Channel::messages`]: enum.Channel.html#method.messages
- /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
- #[inline]
- pub fn messages<F>(&self, f: F) -> Result<Vec<Message>>
- where F: FnOnce(GetMessages) -> GetMessages {
- self.id.messages(f)
- }
-
/// Returns the name of the guild channel.
pub fn name(&self) -> &str { &self.name }
-
- /// Calculates the permissions of a member.
- ///
- /// The Id of the argument must be a [`Member`] of the [`Guild`] that the
- /// channel is in.
- ///
- /// # Examples
- ///
- /// Calculate the permissions of a [`User`] who posted a [`Message`] in a
- /// channel:
- ///
- /// ```rust,no_run
- /// use serenity::prelude::*;
- /// use serenity::model::prelude::*;
- /// struct Handler;
- ///
- /// use serenity::CACHE;
- ///
- /// impl EventHandler for Handler {
- /// fn message(&self, _: Context, msg: Message) {
- /// let channel = match CACHE.read().guild_channel(msg.channel_id) {
- /// Some(channel) => channel,
- /// None => return,
- /// };
- ///
- /// let permissions = channel.read().permissions_for(&msg.author).unwrap();
- ///
- /// println!("The user's permissions: {:?}", permissions);
- /// }
- /// }
- /// let mut client = Client::new("token", Handler).unwrap();
- ///
- /// client.start().unwrap();
- /// ```
- ///
- /// Check if the current user has the [Attach Files] and [Send Messages]
- /// permissions (note: serenity will automatically check this for; this is
- /// for demonstrative purposes):
- ///
- /// ```rust,no_run
- /// use serenity::CACHE;
- /// use serenity::prelude::*;
- /// use serenity::model::prelude::*;
- /// use std::fs::File;
- ///
- /// struct Handler;
- ///
- /// impl EventHandler for Handler {
- /// fn message(&self, _: Context, msg: Message) {
- /// let channel = match CACHE.read().guild_channel(msg.channel_id) {
- /// Some(channel) => channel,
- /// None => return,
- /// };
- ///
- /// let current_user_id = CACHE.read().user.id;
- /// let permissions =
- /// channel.read().permissions_for(current_user_id).unwrap();
- ///
- /// if !permissions.contains(Permissions::ATTACH_FILES | Permissions::SEND_MESSAGES) {
- /// return;
- /// }
- ///
- /// let file = match File::open("./cat.png") {
- /// Ok(file) => file,
- /// Err(why) => {
- /// println!("Err opening file: {:?}", why);
- ///
- /// return;
- /// },
- /// };
- ///
- /// let _ = msg.channel_id.send_files(vec![(&file, "cat.png")], |mut m| {
- /// m.content("here's a cat");
- ///
- /// m
- /// });
- /// }
- /// }
- ///
- /// let mut client = Client::new("token", Handler).unwrap();
- ///
- /// client.start().unwrap();
- /// ```
- ///
- /// # Errors
- ///
- /// Returns a [`ModelError::GuildNotFound`] if the channel's guild could
- /// not be found in the [`Cache`].
- ///
- /// [`Cache`]: ../cache/struct.Cache.html
- /// [`ModelError::GuildNotFound`]: enum.ModelError.html#variant.GuildNotFound
- /// [`Guild`]: struct.Guild.html
- /// [`Member`]: struct.Member.html
- /// [`Message`]: struct.Message.html
- /// [`User`]: struct.User.html
- /// [Attach Files]: permissions/constant.ATTACH_FILES.html
- /// [Send Messages]: permissions/constant.SEND_MESSAGES.html
- #[cfg(feature = "cache")]
- pub fn permissions_for<U: Into<UserId>>(&self, user_id: U) -> Result<Permissions> {
- self.guild()
- .ok_or_else(|| Error::Model(ModelError::GuildNotFound))
- .map(|g| g.read().permissions_in(self.id, user_id))
- }
-
- /// 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.
- #[inline]
- pub fn pins(&self) -> Result<Vec<Message>> { self.id.pins() }
-
- /// Gets the list of [`User`]s who have reacted to a [`Message`] with a
- /// certain [`Emoji`].
- ///
- /// Refer to [`Channel::reaction_users`] for more information.
- ///
- /// **Note**: Requires the [Read Message History] permission.
- ///
- /// [`Channel::reaction_users`]: enum.Channel.html#method.reaction_users
- /// [`Emoji`]: struct.Emoji.html
- /// [`Message`]: struct.Message.html
- /// [`User`]: struct.User.html
- /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
- pub fn reaction_users<M, R, U>(
- &self,
- message_id: M,
- reaction_type: R,
- limit: Option<u8>,
- after: U,
- ) -> Result<Vec<User>> where M: Into<MessageId>,
- R: Into<ReactionType>,
- U: Into<Option<UserId>> {
- self.id.reaction_users(message_id, reaction_type, limit, after)
- }
-
- /// Sends a message with just the given message content in the channel.
- ///
- /// # Errors
- ///
- /// Returns a [`ModelError::MessageTooLong`] if the content of the message
- /// is over the above limit, containing the number of unicode code points
- /// over the limit.
- ///
- /// [`ChannelId`]: struct.ChannelId.html
- /// [`ModelError::MessageTooLong`]: enum.ModelError.html#variant.MessageTooLong
- #[inline]
- pub fn say(&self, content: &str) -> Result<Message> { self.id.say(content) }
-
- /// Sends (a) file(s) along with optional message contents.
- ///
- /// Refer to [`ChannelId::send_files`] for examples and more information.
- ///
- /// The [Attach Files] and [Send Messages] permissions are required.
- ///
- /// **Note**: Message contents must be under 2000 unicode code points.
- ///
- /// # Errors
- ///
- /// If the content of the message is over the above limit, then a
- /// [`ClientError::MessageTooLong`] will be returned, containing the number
- /// of unicode code points over the limit.
- ///
- /// [`ChannelId::send_files`]: struct.ChannelId.html#method.send_files
- /// [`ClientError::MessageTooLong`]: ../client/enum.ClientError.html#variant.MessageTooLong
- /// [Attach Files]: permissions/constant.ATTACH_FILES.html
- /// [Send Messages]: permissions/constant.SEND_MESSAGES.html
- #[inline]
- pub fn send_files<'a, F, T, It: IntoIterator<Item=T>>(&self, files: It, f: F) -> Result<Message>
- where F: FnOnce(CreateMessage) -> CreateMessage, T: Into<AttachmentType<'a>> {
- self.id.send_files(files, f)
- }
-
- /// Sends a message to the channel with the given content.
- ///
- /// **Note**: This will only work when a [`Message`] is received.
- ///
- /// **Note**: Requires the [Send Messages] permission.
- ///
- /// # Errors
- ///
- /// Returns a [`ModelError::MessageTooLong`] if the content of the message
- /// is over the above limit, containing the number of unicode code points
- /// over the limit.
- ///
- /// Returns a [`ModelError::InvalidPermissions`] if the current user does
- /// not have the required permissions.
- ///
- /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
- /// [`ModelError::MessageTooLong`]: enum.ModelError.html#variant.MessageTooLong
- /// [`Message`]: struct.Message.html
- /// [Send Messages]: permissions/constant.SEND_MESSAGES.html
- pub fn send_message<F: FnOnce(CreateMessage) -> CreateMessage>(&self, f: F) -> Result<Message> {
- #[cfg(feature = "cache")]
- {
- let req = Permissions::SEND_MESSAGES;
-
- if !utils::user_has_perms(self.id, req)? {
- return Err(Error::Model(ModelError::InvalidPermissions(req)));
- }
- }
-
- self.id.send_message(f)
- }
-
- /// Unpins a [`Message`] in the channel given by its Id.
- ///
- /// Requires the [Manage Messages] permission.
- ///
- /// [`Message`]: struct.Message.html
- /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
- #[inline]
- pub fn unpin<M: Into<MessageId>>(&self, message_id: M) -> Result<()> {
- self.id.unpin(message_id)
- }
-
- /// 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>> { self.id.webhooks() }
}
-#[cfg(feature = "model")]
impl Display for GuildChannel {
/// Formats the channel, creating a mention of it.
fn fmt(&self, f: &mut Formatter) -> FmtResult { Display::fmt(&self.id.mention(), f) }
diff --git a/src/model/channel/message.rs b/src/model/channel/message.rs
index fdc7787..d0268b0 100644
--- a/src/model/channel/message.rs
+++ b/src/model/channel/message.rs
@@ -1,20 +1,10 @@
//! Models relating to Discord channels.
use chrono::{DateTime, FixedOffset};
+use constants;
use model::prelude::*;
use serde_json::Value;
-#[cfg(feature = "model")]
-use builder::{CreateEmbed, EditMessage};
-#[cfg(all(feature = "cache", feature = "model"))]
-use CACHE;
-#[cfg(all(feature = "cache", feature = "model"))]
-use std::fmt::Write;
-#[cfg(feature = "model")]
-use std::mem;
-#[cfg(feature = "model")]
-use {constants, http, utils as serenity_utils};
-
/// A representation of a message over a guild's text channel, a group, or a
/// private channel.
#[derive(Clone, Debug, Deserialize, Serialize)]
@@ -70,177 +60,8 @@ pub struct Message {
pub webhook_id: Option<WebhookId>,
}
-#[cfg(feature = "model")]
impl Message {
- /// Retrieves the related channel located in the cache.
- ///
- /// Returns `None` if the channel is not in the cache.
- ///
- /// # Examples
- ///
- /// On command, print the name of the channel that a message took place in:
- ///
- /// ```rust,no_run
- /// # #[macro_use] extern crate serenity;
- /// #
- /// # fn main() {
- /// # use serenity::prelude::*;
- /// # struct Handler;
- /// #
- /// # impl EventHandler for Handler {}
- /// # let mut client = Client::new("token", Handler).unwrap();
- /// #
- /// use serenity::model::channel::Channel;
- /// use serenity::framework::StandardFramework;
- ///
- /// client.with_framework(StandardFramework::new()
- /// .configure(|c| c.prefix("~"))
- /// .cmd("channelname", channel_name));
- ///
- /// command!(channel_name(_ctx, msg) {
- /// let _ = match msg.channel() {
- /// Some(Channel::Category(c)) => msg.reply(&c.read().name),
- /// Some(Channel::Group(c)) => msg.reply(&c.read().name()),
- /// Some(Channel::Guild(c)) => msg.reply(&c.read().name),
- /// Some(Channel::Private(c)) => {
- /// let channel = c.read();
- /// let user = channel.recipient.read();
- ///
- /// msg.reply(&format!("DM with {}", user.name.clone()))
- /// },
- /// None => msg.reply("Unknown"),
- /// };
- /// });
- /// # }
- /// ```
- #[cfg(feature = "cache")]
- #[inline]
- pub fn channel(&self) -> Option<Channel> { CACHE.read().channel(self.channel_id) }
-
- /// A util function for determining whether this message was sent by someone else, or the
- /// bot.
- #[cfg(all(feature = "cache", feature = "utils"))]
- pub fn is_own(&self) -> bool { self.author.id == CACHE.read().user.id }
-
- /// Deletes the message.
- ///
- /// **Note**: The logged in user must either be the author of the message or
- /// have the [Manage Messages] permission.
- ///
- /// # Errors
- ///
- /// If the `cache` feature is enabled, then returns a
- /// [`ModelError::InvalidPermissions`] if the current user does not have
- /// the required permissions.
- ///
- /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
- /// [`ModelError::InvalidUser`]: enum.ModelError.html#variant.InvalidUser
- /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
- pub fn delete(&self) -> Result<()> {
- #[cfg(feature = "cache")]
- {
- let req = Permissions::MANAGE_MESSAGES;
- let is_author = self.author.id == CACHE.read().user.id;
- let has_perms = utils::user_has_perms(self.channel_id, req)?;
-
- if !is_author && !has_perms {
- return Err(Error::Model(ModelError::InvalidPermissions(req)));
- }
- }
-
- self.channel_id.delete_message(self.id)
- }
-
- /// Deletes all of the [`Reaction`]s associated with the message.
- ///
- /// **Note**: Requires the [Manage Messages] permission.
- ///
- /// # Errors
- ///
- /// If the `cache` feature is enabled, then returns a
- /// [`ModelError::InvalidPermissions`] if the current user does not have
- /// the required permissions.
- ///
- /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
- /// [`Reaction`]: struct.Reaction.html
- /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
- pub fn delete_reactions(&self) -> Result<()> {
- #[cfg(feature = "cache")]
- {
- let req = Permissions::MANAGE_MESSAGES;
-
- if !utils::user_has_perms(self.channel_id, req)? {
- return Err(Error::Model(ModelError::InvalidPermissions(req)));
- }
- }
-
- http::delete_message_reactions(self.channel_id.0, self.id.0)
- }
-
- /// Edits this message, replacing the original content with new content.
- ///
- /// Message editing preserves all unchanged message data.
- ///
- /// Refer to the documentation for [`EditMessage`] for more information
- /// regarding message restrictions and requirements.
- ///
- /// **Note**: Requires that the current user be the author of the message.
- ///
- /// # Examples
- ///
- /// Edit a message with new content:
- ///
- /// ```rust,ignore
- /// // assuming a `message` has already been bound
- ///
- /// message.edit(|m| m.content("new content"));
- /// ```
- ///
- /// # Errors
- ///
- /// If the `cache` is enabled, returns a [`ModelError::InvalidUser`] if the
- /// current user is not the author.
- ///
- /// Returns a [`ModelError::MessageTooLong`] if the content of the message
- /// is over [`the limit`], containing the number of unicode code points
- /// over the limit.
- ///
- /// [`ModelError::InvalidUser`]: enum.ModelError.html#variant.InvalidUser
- /// [`ModelError::MessageTooLong`]: enum.ModelError.html#variant.MessageTooLong
- /// [`EditMessage`]: ../builder/struct.EditMessage.html
- /// [`the limit`]: ../builder/struct.EditMessage.html#method.content
- pub fn edit<F>(&mut self, f: F) -> Result<()>
- where F: FnOnce(EditMessage) -> EditMessage {
- #[cfg(feature = "cache")]
- {
- if self.author.id != CACHE.read().user.id {
- return Err(Error::Model(ModelError::InvalidUser));
- }
- }
-
- let mut builder = EditMessage::default();
-
- if !self.content.is_empty() {
- builder.content(&self.content);
- }
-
- if let Some(embed) = self.embeds.get(0) {
- builder.embed(|_| CreateEmbed::from(embed.clone()));
- }
-
- let map = serenity_utils::vecmap_to_json_map(f(builder).0);
-
- match http::edit_message(self.channel_id.0, self.id.0, &Value::Object(map)) {
- Ok(edited) => {
- mem::replace(self, edited);
-
- Ok(())
- },
- Err(why) => Err(why),
- }
- }
-
- pub(crate) fn transform_content(&mut self) {
+ pub fn transform_content(&mut self) {
match self.kind {
MessageType::PinsAdd => {
self.content = format!(
@@ -262,115 +83,6 @@ impl Message {
}
}
- /// Returns message content, but with user and role mentions replaced with
- /// names and everyone/here mentions cancelled.
- #[cfg(feature = "cache")]
- pub fn content_safe(&self) -> String {
- let mut result = self.content.clone();
-
- // First replace all user mentions.
- for u in &self.mentions {
- let mut at_distinct = String::with_capacity(38);
- at_distinct.push('@');
- at_distinct.push_str(&u.name);
- at_distinct.push('#');
- let _ = write!(at_distinct, "{:04}", u.discriminator);
- result = result.replace(&u.mention(), &at_distinct);
- }
-
- // Then replace all role mentions.
- for id in &self.mention_roles {
- let mention = id.mention();
-
- if let Some(role) = id.find() {
- result = result.replace(&mention, &format!("@{}", role.name));
- } else {
- result = result.replace(&mention, "@deleted-role");
- }
- }
-
- // And finally replace everyone and here mentions.
- result
- .replace("@everyone", "@\u{200B}everyone")
- .replace("@here", "@\u{200B}here")
- }
-
- /// Gets the list of [`User`]s who have reacted to a [`Message`] with a
- /// certain [`Emoji`].
- ///
- /// The default `limit` is `50` - specify otherwise to receive a different
- /// maximum number of users. The maximum that may be retrieve at a time is
- /// `100`, if a greater number is provided then it is automatically reduced.
- ///
- /// The optional `after` attribute is to retrieve the users after a certain
- /// user. This is useful for pagination.
- ///
- /// **Note**: Requires the [Read Message History] permission.
- ///
- /// [`Emoji`]: struct.Emoji.html
- /// [`Message`]: struct.Message.html
- /// [`User`]: struct.User.html
- /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
- #[inline]
- pub fn reaction_users<R, U>(
- &self,
- reaction_type: R,
- limit: Option<u8>,
- after: U,
- ) -> Result<Vec<User>> where R: Into<ReactionType>,
- U: Into<Option<UserId>> {
- self.channel_id.reaction_users(self.id, reaction_type, limit, after)
- }
-
- /// Returns the associated `Guild` for the message if one is in the cache.
- ///
- /// Returns `None` if the guild's Id could not be found via [`guild_id`] or
- /// if the Guild itself is not cached.
- ///
- /// Requires the `cache` feature be enabled.
- ///
- /// [`guild_id`]: #method.guild_id
- #[cfg(feature = "cache")]
- pub fn guild(&self) -> Option<Arc<RwLock<Guild>>> {
- self.guild_id()
- .and_then(|guild_id| CACHE.read().guild(guild_id))
- }
-
- /// Retrieves the Id of the guild that the message was sent in, if sent in
- /// one.
- ///
- /// Returns `None` if the channel data or guild data does not exist in the
- /// cache.
- #[cfg(feature = "cache")]
- pub fn guild_id(&self) -> Option<GuildId> {
- match CACHE.read().channel(self.channel_id) {
- Some(Channel::Guild(ch)) => Some(ch.read().guild_id),
- _ => None,
- }
- }
-
- /// True if message was sent using direct messages.
- #[cfg(feature = "cache")]
- pub fn is_private(&self) -> bool {
- match CACHE.read().channel(self.channel_id) {
- Some(Channel::Group(_)) | Some(Channel::Private(_)) => true,
- _ => false,
- }
- }
-
- /// Retrieves a clone of the author's Member instance, if this message was
- /// sent in a guild.
- ///
- /// Note that since this clones, it is preferable performance-wise to
- /// manually retrieve the guild from the cache and access
- /// [`Guild::members`].
- ///
- /// [`Guild::members`]: ../guild/struct.Guild.html#structfield.members
- #[cfg(feature = "cache")]
- pub fn member(&self) -> Option<Member> {
- self.guild().and_then(|g| g.read().members.get(&self.author.id).cloned())
- }
-
/// Checks the length of a string to ensure that it is within Discord's
/// maximum message length limit.
///
@@ -390,132 +102,7 @@ impl Message {
}
}
- /// Pins this message to its channel.
- ///
- /// **Note**: Requires the [Manage Messages] permission.
- ///
- /// # Errors
- ///
- /// If the `cache` is enabled, returns a
- /// [`ModelError::InvalidPermissions`] if the current user does not have
- /// the required permissions.
- ///
- /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
- /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
- pub fn pin(&self) -> Result<()> {
- #[cfg(feature = "cache")]
- {
- let req = Permissions::MANAGE_MESSAGES;
-
- if !utils::user_has_perms(self.channel_id, req)? {
- return Err(Error::Model(ModelError::InvalidPermissions(req)));
- }
- }
-
- self.channel_id.pin(self.id.0)
- }
-
- /// React to the message with a custom [`Emoji`] or unicode character.
- ///
- /// **Note**: Requires the [Add Reactions] permission.
- ///
- /// # Errors
- ///
- /// If the `cache` is enabled, returns a
- /// [`ModelError::InvalidPermissions`] if the current user does not have the
- /// required [permissions].
- ///
- /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
- /// [`Emoji`]: struct.Emoji.html
- /// [Add Reactions]: permissions/constant.ADD_REACTIONS.html
- /// [permissions]: permissions
- pub fn react<R: Into<ReactionType>>(&self, reaction_type: R) -> Result<()> {
- #[cfg(feature = "cache")]
- {
- let req = Permissions::ADD_REACTIONS;
-
- if !utils::user_has_perms(self.channel_id, req)? {
- return Err(Error::Model(ModelError::InvalidPermissions(req)));
- }
- }
-
- http::create_reaction(self.channel_id.0, self.id.0, &reaction_type.into())
- }
-
- /// Replies to the user, mentioning them prior to the content in the form
- /// of: `@<USER_ID>: YOUR_CONTENT`.
- ///
- /// User mentions are generally around 20 or 21 characters long.
- ///
- /// **Note**: Requires the [Send Messages] permission.
- ///
- /// **Note**: Message contents must be under 2000 unicode code points.
- ///
- /// # Errors
- ///
- /// If the `cache` is enabled, returns a
- /// [`ModelError::InvalidPermissions`] if the current user does not have
- /// the required permissions.
- ///
- /// Returns a [`ModelError::MessageTooLong`] if the content of the message
- /// is over the above limit, containing the number of unicode code points
- /// over the limit.
- ///
- /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
- /// [`ModelError::MessageTooLong`]: enum.ModelError.html#variant.MessageTooLong
- /// [Send Messages]: permissions/constant.SEND_MESSAGES.html
- pub fn reply(&self, content: &str) -> Result<Message> {
- if let Some(length_over) = Message::overflow_length(content) {
- return Err(Error::Model(ModelError::MessageTooLong(length_over)));
- }
-
- #[cfg(feature = "cache")]
- {
- let req = Permissions::SEND_MESSAGES;
-
- if !utils::user_has_perms(self.channel_id, req)? {
- return Err(Error::Model(ModelError::InvalidPermissions(req)));
- }
- }
-
- let mut gen = self.author.mention();
- gen.push_str(": ");
- gen.push_str(content);
-
- let map = json!({
- "content": gen,
- "tts": false,
- });
-
- http::send_message(self.channel_id.0, &map)
- }
-
- /// Unpins the message from its channel.
- ///
- /// **Note**: Requires the [Manage Messages] permission.
- ///
- /// # Errors
- ///
- /// If the `cache` is enabled, returns a
- /// [`ModelError::InvalidPermissions`] if the current user does not have
- /// the required permissions.
- ///
- /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
- /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
- pub fn unpin(&self) -> Result<()> {
- #[cfg(feature = "cache")]
- {
- let req = Permissions::MANAGE_MESSAGES;
-
- if !utils::user_has_perms(self.channel_id, req)? {
- return Err(Error::Model(ModelError::InvalidPermissions(req)));
- }
- }
-
- http::unpin_message(self.channel_id.0, self.id.0)
- }
-
- pub(crate) fn check_content_length(map: &JsonMap) -> Result<()> {
+ pub fn check_content_length(map: &JsonMap) -> Result<()> {
if let Some(content) = map.get("content") {
if let Value::String(ref content) = *content {
if let Some(length_over) = Message::overflow_length(content) {
@@ -527,7 +114,7 @@ impl Message {
Ok(())
}
- pub(crate) fn check_embed_length(map: &JsonMap) -> Result<()> {
+ pub fn check_embed_length(map: &JsonMap) -> Result<()> {
let embed = match map.get("embed") {
Some(&Value::Object(ref value)) => value,
_ => return Ok(()),
diff --git a/src/model/channel/mod.rs b/src/model/channel/mod.rs
index 8d586a6..384bb34 100644
--- a/src/model/channel/mod.rs
+++ b/src/model/channel/mod.rs
@@ -20,48 +20,38 @@ pub use self::private_channel::*;
pub use self::reaction::*;
pub use self::channel_category::*;
-use internal::RwLockExt;
use model::prelude::*;
use serde::de::Error as DeError;
use serde::ser::{SerializeStruct, Serialize, Serializer};
use serde_json;
-use super::utils::deserialize_u64;
-
-#[cfg(feature = "model")]
-use builder::{CreateMessage, EditMessage, GetMessages};
-#[cfg(feature = "model")]
-use http::AttachmentType;
-#[cfg(feature = "model")]
+use std::cell::RefCell;
use std::fmt::{Display, Formatter, Result as FmtResult};
+use std::rc::Rc;
+use super::utils::deserialize_u64;
/// A container for any channel.
#[derive(Clone, Debug)]
pub enum Channel {
/// A group. A group comprises of only one channel.
- Group(Arc<RwLock<Group>>),
+ Group(Rc<RefCell<Group>>),
/// A [text] or [voice] channel within a [`Guild`].
///
/// [`Guild`]: struct.Guild.html
/// [text]: enum.ChannelType.html#variant.Text
/// [voice]: enum.ChannelType.html#variant.Voice
- Guild(Arc<RwLock<GuildChannel>>),
+ Guild(Rc<RefCell<GuildChannel>>),
/// A private channel to another [`User`]. No other users may access the
/// channel. For multi-user "private channels", use a group.
///
/// [`User`]: struct.User.html
- Private(Arc<RwLock<PrivateChannel>>),
+ Private(Rc<RefCell<PrivateChannel>>),
/// A category of [`GuildChannel`]s
///
/// [`GuildChannel`]: struct.GuildChannel.html
- Category(Arc<RwLock<ChannelCategory>>),
+ Category(Rc<RefCell<ChannelCategory>>),
}
impl Channel {
-
- /////////////////////////////////////////////////////////////////////////
- // Adapter for each variant
- /////////////////////////////////////////////////////////////////////////
-
/// Converts from `Channel` to `Option<Arc<RwLock<Group>>>`.
///
/// Converts `self` into an `Option<Arc<RwLock<Group>>>`, consuming `self`,
@@ -88,9 +78,7 @@ impl Channel {
/// }
/// # }
/// ```
-
-
- pub fn group(self) -> Option<Arc<RwLock<Group>>> {
+ pub fn group(self) -> Option<Rc<RefCell<Group>>> {
match self {
Channel::Group(lock) => Some(lock),
_ => None,
@@ -119,8 +107,7 @@ impl Channel {
/// }
/// # }
/// ```
-
- pub fn guild(self) -> Option<Arc<RwLock<GuildChannel>>> {
+ pub fn guild(self) -> Option<Rc<RefCell<GuildChannel>>> {
match self {
Channel::Guild(lock) => Some(lock),
_ => None,
@@ -152,8 +139,7 @@ impl Channel {
/// }
/// # }
/// ```
-
- pub fn private(self) -> Option<Arc<RwLock<PrivateChannel>>> {
+ pub fn private(self) -> Option<Rc<RefCell<PrivateChannel>>> {
match self {
Channel::Private(lock) => Some(lock),
_ => None,
@@ -182,124 +168,13 @@ impl Channel {
/// }
/// # }
/// ```
-
- pub fn category(self) -> Option<Arc<RwLock<ChannelCategory>>> {
+ pub fn category(self) -> Option<Rc<RefCell<ChannelCategory>>> {
match self {
Channel::Category(lock) => Some(lock),
_ => None,
}
}
- /// React to a [`Message`] with a custom [`Emoji`] or unicode character.
- ///
- /// [`Message::react`] may be a more suited method of reacting in most
- /// cases.
- ///
- /// Requires the [Add Reactions] permission, _if_ the current user is the
- /// first user to perform a react with a certain emoji.
- ///
- /// [`Emoji`]: struct.Emoji.html
- /// [`Message`]: struct.Message.html
- /// [`Message::react`]: struct.Message.html#method.react
- /// [Add Reactions]: permissions/constant.ADD_REACTIONS.html
- #[cfg(feature = "model")]
- #[deprecated(since = "0.4.2", note = "Use the inner channel's method")]
- #[inline]
- pub fn create_reaction<M, R>(&self, message_id: M, reaction_type: R) -> Result<()>
- where M: Into<MessageId>, R: Into<ReactionType> {
- self.id().create_reaction(message_id, reaction_type)
- }
-
- /// Deletes the inner channel.
- ///
- /// **Note**: There is no real function as _deleting_ a [`Group`]. The
- /// closest functionality is leaving it.
- ///
- /// [`Group`]: struct.Group.html
- #[cfg(feature = "model")]
- pub fn delete(&self) -> Result<()> {
- match *self {
- Channel::Group(ref group) => {
- let _ = group.read().leave()?;
- },
- Channel::Guild(ref public_channel) => {
- let _ = public_channel.read().delete()?;
- },
- Channel::Private(ref private_channel) => {
- let _ = private_channel.read().delete()?;
- },
- Channel::Category(ref category) => {
- category.read().delete()?;
- },
- }
-
- Ok(())
- }
-
- /// Deletes a [`Message`] given its Id.
- ///
- /// Refer to [`Message::delete`] for more information.
- ///
- /// Requires the [Manage Messages] permission, if the current user is not
- /// the author of the message.
- ///
- /// [`Message`]: struct.Message.html
- /// [`Message::delete`]: struct.Message.html#method.delete
- /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
- #[cfg(feature = "model")]
- #[deprecated(since = "0.4.2", note = "Use the inner channel's method")]
- #[inline]
- pub fn delete_message<M: Into<MessageId>>(&self, message_id: M) -> Result<()> {
- self.id().delete_message(message_id)
- }
-
- /// Deletes the given [`Reaction`] from the channel.
- ///
- /// **Note**: Requires the [Manage Messages] permission, _if_ the current
- /// user did not perform the reaction.
- ///
- /// [`Reaction`]: struct.Reaction.html
- /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
- #[cfg(feature = "model")]
- #[deprecated(since = "0.4.2", note = "Use the inner channel's method")]
- #[inline]
- pub fn delete_reaction<M, R>(&self,
- message_id: M,
- user_id: Option<UserId>,
- reaction_type: R)
- -> Result<()>
- where M: Into<MessageId>, R: Into<ReactionType> {
- self.id()
- .delete_reaction(message_id, user_id, reaction_type)
- }
-
- /// Edits a [`Message`] in the channel given its Id.
- ///
- /// Message editing preserves all unchanged message data.
- ///
- /// Refer to the documentation for [`EditMessage`] for more information
- /// regarding message restrictions and requirements.
- ///
- /// **Note**: Requires that the current user be the author of the message.
- ///
- /// # Errors
- ///
- /// Returns a [`ModelError::MessageTooLong`] if the content of the message
- /// is over the [`the limit`], containing the number of unicode code points
- /// over the limit.
- ///
- /// [`ModelError::MessageTooLong`]: enum.ModelError.html#variant.MessageTooLong
- /// [`EditMessage`]: ../builder/struct.EditMessage.html
- /// [`Message`]: struct.Message.html
- /// [`the limit`]: ../builder/struct.EditMessage.html#method.content
- #[cfg(feature = "model")]
- #[deprecated(since = "0.4.2", note = "Use the inner channel's method")]
- #[inline]
- pub fn edit_message<F, M>(&self, message_id: M, f: F) -> Result<Message>
- where F: FnOnce(EditMessage) -> EditMessage, M: Into<MessageId> {
- self.id().edit_message(message_id, f)
- }
-
/// Determines if the channel is NSFW.
///
/// Refer to [`utils::is_nsfw`] for more details.
@@ -309,78 +184,12 @@ impl Channel {
#[inline]
pub fn is_nsfw(&self) -> bool {
match *self {
- Channel::Guild(ref channel) => channel.with(|c| c.is_nsfw()),
- Channel::Category(ref category) => category.with(|c| c.is_nsfw()),
+ Channel::Guild(ref channel) => channel.borrow().is_nsfw(),
+ Channel::Category(ref category) => category.borrow().is_nsfw(),
Channel::Group(_) | Channel::Private(_) => false,
}
}
- /// Gets a message from the channel.
- ///
- /// Requires the [Read Message History] permission.
- ///
- /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
- #[cfg(feature = "model")]
- #[deprecated(since = "0.4.2", note = "Use the inner channel's method")]
- #[inline]
- pub fn message<M: Into<MessageId>>(&self, message_id: M) -> Result<Message> {
- self.id().message(message_id)
- }
-
- /// Gets messages from the channel.
- ///
- /// Requires the [Read Message History] permission.
- ///
- /// # Examples
- ///
- /// ```rust,ignore
- /// use serenity::model::MessageId;
- ///
- /// let id = MessageId(81392407232380928);
- ///
- /// // Maximum is 100.
- /// let _messages = channel.messages(|g| g.after(id).limit(100));
- /// ```
- ///
- /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
- #[cfg(feature = "model")]
- #[deprecated(since = "0.4.2", note = "Use the inner channel's method")]
- #[inline]
- pub fn messages<F>(&self, f: F) -> Result<Vec<Message>>
- where F: FnOnce(GetMessages) -> GetMessages {
- self.id().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
- #[cfg(feature = "model")]
- #[deprecated(since = "0.4.2", note = "Use the inner channel's method")]
- #[inline]
- pub fn reaction_users<M, R, U>(&self,
- message_id: M,
- reaction_type: R,
- limit: Option<u8>,
- after: U,
- ) -> Result<Vec<User>> where M: Into<MessageId>,
- R: Into<ReactionType>,
- U: Into<Option<UserId>> {
- self.id().reaction_users(message_id, reaction_type, limit, after)
- }
-
/// Retrieves the Id of the inner [`Group`], [`GuildChannel`], or
/// [`PrivateChannel`].
///
@@ -389,93 +198,12 @@ impl Channel {
/// [`PrivateChannel`]: struct.PrivateChannel.html
pub fn id(&self) -> ChannelId {
match *self {
- Channel::Group(ref group) => group.with(|g| g.channel_id),
- Channel::Guild(ref ch) => ch.with(|c| c.id),
- Channel::Private(ref ch) => ch.with(|c| c.id),
- Channel::Category(ref category) => category.with(|c| c.id),
+ Channel::Group(ref group) => group.borrow().channel_id,
+ Channel::Guild(ref ch) => ch.borrow().id,
+ Channel::Private(ref ch) => ch.borrow().id,
+ Channel::Category(ref category) => category.borrow().id,
}
}
-
- /// Sends a message with just the given message content in the channel.
- ///
- /// # Errors
- ///
- /// Returns a [`ModelError::MessageTooLong`] if the content of the message
- /// is over the above limit, containing the number of unicode code points
- /// over the limit.
- ///
- /// [`ChannelId`]: struct.ChannelId.html
- /// [`ModelError::MessageTooLong`]: enum.ModelError.html#variant.MessageTooLong
- #[cfg(feature = "model")]
- #[deprecated(since = "0.4.2", note = "Use the inner channel's method")]
- #[inline]
- pub fn say(&self, content: &str) -> Result<Message> { self.id().say(content) }
-
- /// Sends (a) file(s) along with optional message contents.
- ///
- /// Refer to [`ChannelId::send_files`] for examples and more information.
- ///
- /// The [Attach Files] and [Send Messages] permissions are required.
- ///
- /// **Note**: Message contents must be under 2000 unicode code points.
- ///
- /// # Errors
- ///
- /// If the content of the message is over the above limit, then a
- /// [`ClientError::MessageTooLong`] will be returned, containing the number
- /// of unicode code points over the limit.
- ///
- /// [`ChannelId::send_files`]: struct.ChannelId.html#method.send_files
- /// [`ClientError::MessageTooLong`]: ../client/enum.ClientError.html#variant.MessageTooLong
- /// [Attach Files]: permissions/constant.ATTACH_FILES.html
- /// [Send Messages]: permissions/constant.SEND_MESSAGES.html
- #[cfg(feature = "model")]
- #[deprecated(since = "0.4.2", note = "Use the inner channel's method")]
- #[inline]
- pub fn send_files<'a, F, T, It: IntoIterator<Item=T>>(&self, files: It, f: F) -> Result<Message>
- where F: FnOnce(CreateMessage) -> CreateMessage, T: Into<AttachmentType<'a>> {
- self.id().send_files(files, f)
- }
-
- /// Sends a message to the channel.
- ///
- /// Refer to the documentation for [`CreateMessage`] for more information
- /// regarding message restrictions and requirements.
- ///
- /// The [Send Messages] permission is required.
- ///
- /// **Note**: Message contents must be under 2000 unicode code points.
- ///
- /// # Errors
- ///
- /// Returns a [`ModelError::MessageTooLong`] if the content of the message
- /// is over the above limit, containing the number of unicode code points
- /// over the limit.
- ///
- /// [`Channel`]: enum.Channel.html
- /// [`ModelError::MessageTooLong`]: enum.ModelError.html#variant.MessageTooLong
- /// [`CreateMessage`]: ../builder/struct.CreateMessage.html
- /// [Send Messages]: permissions/constant.SEND_MESSAGES.html
- #[cfg(feature = "model")]
- #[deprecated(since = "0.4.2", note = "Use the inner channel's method")]
- #[inline]
- pub fn send_message<F>(&self, f: F) -> Result<Message>
- where F: FnOnce(CreateMessage) -> CreateMessage {
- self.id().send_message(f)
- }
-
- /// Unpins a [`Message`] in the channel given by its Id.
- ///
- /// Requires the [Manage Messages] permission.
- ///
- /// [`Message`]: struct.Message.html
- /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
- #[cfg(feature = "model")]
- #[deprecated(since = "0.4.2", note = "Use the inner channel's method")]
- #[inline]
- pub fn unpin<M: Into<MessageId>>(&self, message_id: M) -> Result<()> {
- self.id().unpin(message_id)
- }
}
impl<'de> Deserialize<'de> for Channel {
@@ -489,16 +217,16 @@ impl<'de> Deserialize<'de> for Channel {
match kind {
0 | 2 => serde_json::from_value::<GuildChannel>(Value::Object(v))
- .map(|x| Channel::Guild(Arc::new(RwLock::new(x))))
+ .map(|x| Channel::Guild(Rc::new(RefCell::new(x))))
.map_err(DeError::custom),
1 => serde_json::from_value::<PrivateChannel>(Value::Object(v))
- .map(|x| Channel::Private(Arc::new(RwLock::new(x))))
+ .map(|x| Channel::Private(Rc::new(RefCell::new(x))))
.map_err(DeError::custom),
3 => serde_json::from_value::<Group>(Value::Object(v))
- .map(|x| Channel::Group(Arc::new(RwLock::new(x))))
+ .map(|x| Channel::Group(Rc::new(RefCell::new(x))))
.map_err(DeError::custom),
4 => serde_json::from_value::<ChannelCategory>(Value::Object(v))
- .map(|x| Channel::Category(Arc::new(RwLock::new(x))))
+ .map(|x| Channel::Category(Rc::new(RefCell::new(x))))
.map_err(DeError::custom),
_ => Err(DeError::custom("Unknown channel type")),
}
@@ -510,22 +238,21 @@ impl Serialize for Channel {
where S: Serializer {
match *self {
Channel::Category(ref c) => {
- ChannelCategory::serialize(&*c.read(), serializer)
+ ChannelCategory::serialize(&*c.borrow(), serializer)
},
Channel::Group(ref c) => {
- Group::serialize(&*c.read(), serializer)
+ Group::serialize(&*c.borrow(), serializer)
},
Channel::Guild(ref c) => {
- GuildChannel::serialize(&*c.read(), serializer)
+ GuildChannel::serialize(&*c.borrow(), serializer)
},
Channel::Private(ref c) => {
- PrivateChannel::serialize(&*c.read(), serializer)
+ PrivateChannel::serialize(&*c.borrow(), serializer)
},
}
}
}
-#[cfg(feature = "model")]
impl Display for Channel {
/// Formats the channel into a "mentioned" string.
///
@@ -542,15 +269,15 @@ impl Display for Channel {
/// [`PrivateChannel`]: struct.PrivateChannel.html
fn fmt(&self, f: &mut Formatter) -> FmtResult {
match *self {
- Channel::Group(ref group) => Display::fmt(&group.read().name(), f),
- Channel::Guild(ref ch) => Display::fmt(&ch.read().id.mention(), f),
+ Channel::Group(ref group) => Display::fmt(&group.borrow().name(), f),
+ Channel::Guild(ref ch) => Display::fmt(&ch.borrow().id.mention(), f),
Channel::Private(ref ch) => {
- let channel = ch.read();
- let recipient = channel.recipient.read();
+ let channel = ch.borrow();
+ let recipient = channel.recipient.borrow();
Display::fmt(&recipient.name, f)
},
- Channel::Category(ref category) => Display::fmt(&category.read().name, f),
+ Channel::Category(ref category) => Display::fmt(&category.borrow().name, f),
}
}
}
diff --git a/src/model/channel/private_channel.rs b/src/model/channel/private_channel.rs
index 91a019c..74f6785 100644
--- a/src/model/channel/private_channel.rs
+++ b/src/model/channel/private_channel.rs
@@ -1,23 +1,10 @@
use chrono::{DateTime, FixedOffset};
use model::prelude::*;
-use std::fmt::{
- Display,
- Formatter,
- Result as FmtResult
-};
+use std::cell::RefCell;
+use std::fmt::{Display, Formatter, Result as FmtResult};
+use std::rc::Rc;
use super::deserialize_single_recipient;
-#[cfg(feature = "model")]
-use builder::{
- CreateMessage,
- EditMessage,
- GetMessages
-};
-#[cfg(feature = "model")]
-use http::AttachmentType;
-#[cfg(feature = "model")]
-use internal::RwLockExt;
-
/// A Direct Message text channel with another user.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct PrivateChannel {
@@ -41,257 +28,20 @@ pub struct PrivateChannel {
/// The recipient to the private channel.
#[serde(deserialize_with = "deserialize_single_recipient",
rename = "recipients",
- serialize_with = "serialize_sync_user")]
- pub recipient: Arc<RwLock<User>>,
+ serialize_with = "serialize_user")]
+ pub recipient: Rc<RefCell<User>>,
}
-#[cfg(feature = "model")]
impl PrivateChannel {
- /// Broadcasts that the current user is typing to the recipient.
- pub fn broadcast_typing(&self) -> Result<()> { self.id.broadcast_typing() }
-
- /// React to a [`Message`] with a custom [`Emoji`] or unicode character.
- ///
- /// [`Message::react`] may be a more suited method of reacting in most
- /// cases.
- ///
- /// Requires the [Add Reactions] permission, _if_ the current user is the
- /// first user to perform a react with a certain emoji.
- ///
- /// [`Emoji`]: struct.Emoji.html
- /// [`Message`]: struct.Message.html
- /// [`Message::react`]: struct.Message.html#method.react
- /// [Add Reactions]: permissions/constant.ADD_REACTIONS.html
- 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)
- }
-
- /// Deletes the channel. This does not delete the contents of the channel,
- /// and is equivalent to closing a private channel on the client, which can
- /// be re-opened.
- #[inline]
- pub fn delete(&self) -> Result<Channel> { 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**: Messages that are older than 2 weeks can't be deleted using
- /// this method.
- ///
- /// # Errors
- ///
- /// Returns [`ModelError::BulkDeleteAmount`] if an attempt was made to
- /// delete either 0 or more than 100 messages.
- ///
- /// [`Channel::delete_messages`]: enum.Channel.html#method.delete_messages
- /// [`ModelError::BulkDeleteAmount`]: ../enum.ModelError.html#variant.BulkDeleteAmount
- /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
- #[inline]
- pub fn delete_messages<T: AsRef<MessageId>, It: IntoIterator<Item=T>>(&self, message_ids: It) -> Result<()> {
- self.id.delete_messages(message_ids)
- }
-
- /// Deletes all permission overrides in the channel from a member
- /// or role.
- ///
- /// **Note**: Requires the [Manage Channel] permission.
- ///
- /// [Manage Channel]: permissions/constant.MANAGE_CHANNELS.html
- #[inline]
- pub fn delete_permission(&self, permission_type: PermissionOverwriteType) -> Result<()> {
- self.id.delete_permission(permission_type)
- }
-
- /// Deletes the given [`Reaction`] from the channel.
- ///
- /// **Note**: Requires the [Manage Messages] permission, _if_ the current
- /// user did not perform the reaction.
- ///
- /// [`Reaction`]: struct.Reaction.html
- /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
- #[inline]
- pub fn delete_reaction<M, R>(&self,
- message_id: M,
- user_id: Option<UserId>,
- reaction_type: R)
- -> Result<()>
- where M: Into<MessageId>, R: Into<ReactionType> {
- self.id.delete_reaction(message_id, user_id, reaction_type)
- }
-
- /// Edits a [`Message`] in the channel given its Id.
- ///
- /// Message editing preserves all unchanged message data.
- ///
- /// Refer to the documentation for [`EditMessage`] for more information
- /// regarding message restrictions and requirements.
- ///
- /// **Note**: Requires that the current user be the author of the message.
- ///
- /// # Errors
- ///
- /// Returns a [`ModelError::MessageTooLong`] if the content of the message
- /// is over the [`the limit`], containing the number of unicode code points
- /// over the limit.
- ///
- /// [`ModelError::MessageTooLong`]: enum.ModelError.html#variant.MessageTooLong
- /// [`EditMessage`]: ../builder/struct.EditMessage.html
- /// [`Message`]: struct.Message.html
- /// [`the limit`]: ../builder/struct.EditMessage.html#method.content
- #[inline]
- pub fn edit_message<F, M>(&self, message_id: M, f: F) -> Result<Message>
- where F: FnOnce(EditMessage) -> EditMessage, M: Into<MessageId> {
- self.id.edit_message(message_id, f)
- }
-
- /// Determines if the channel is NSFW.
- ///
- /// Refer to [`utils::is_nsfw`] for more details.
- ///
- /// **Note**: This method is for consistency. This will always return
- /// `false`, due to DMs not being considered NSFW.
- ///
- /// [`utils::is_nsfw`]: ../../utils/fn.is_nsfw.html
- #[inline]
- pub fn is_nsfw(&self) -> bool { false }
-
- /// Gets a message from the channel.
- ///
- /// Requires the [Read Message History] permission.
- ///
- /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
- #[inline]
- pub fn message<M: Into<MessageId>>(&self, message_id: M) -> Result<Message> {
- self.id.message(message_id)
- }
-
- /// Gets messages from the channel.
- ///
- /// Refer to [`Channel::messages`] for more information.
- ///
- /// Requires the [Read Message History] permission.
- ///
- /// [`Channel::messages`]: enum.Channel.html#method.messages
- /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
- #[inline]
- pub fn messages<F>(&self, f: F) -> Result<Vec<Message>>
- where F: FnOnce(GetMessages) -> GetMessages {
- self.id.messages(f)
- }
-
/// Returns "DM with $username#discriminator".
- pub fn name(&self) -> String { format!("DM with {}", self.recipient.with(|r| r.tag())) }
-
- /// Gets the list of [`User`]s who have reacted to a [`Message`] with a
- /// certain [`Emoji`].
- ///
- /// Refer to [`Channel::reaction_users`] for more information.
- ///
- /// **Note**: Requires the [Read Message History] permission.
- ///
- /// [`Channel::reaction_users`]: enum.Channel.html#method.reaction_users
- /// [`Emoji`]: struct.Emoji.html
- /// [`Message`]: struct.Message.html
- /// [`User`]: struct.User.html
- /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
- #[inline]
- pub fn reaction_users<M, R, U>(&self,
- message_id: M,
- reaction_type: R,
- limit: Option<u8>,
- after: U,
- ) -> Result<Vec<User>> where M: Into<MessageId>,
- R: Into<ReactionType>,
- U: Into<Option<UserId>> {
- self.id.reaction_users(message_id, reaction_type, limit, after)
- }
-
- /// Pins a [`Message`] to the channel.
- ///
- /// [`Message`]: struct.Message.html
- #[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.
- #[inline]
- pub fn pins(&self) -> Result<Vec<Message>> { self.id.pins() }
-
- /// Sends a message with just the given message content in the channel.
- ///
- /// # Errors
- ///
- /// Returns a [`ModelError::MessageTooLong`] if the content of the message
- /// is over the above limit, containing the number of unicode code points
- /// over the limit.
- ///
- /// [`ChannelId`]: ../model/id/struct.ChannelId.html
- /// [`ModelError::MessageTooLong`]: enum.ModelError.html#variant.MessageTooLong
- #[inline]
- pub fn say<D: ::std::fmt::Display>(&self, content: D) -> Result<Message> { self.id.say(content) }
-
- /// Sends (a) file(s) along with optional message contents.
- ///
- /// Refer to [`ChannelId::send_files`] for examples and more information.
- ///
- /// The [Attach Files] and [Send Messages] permissions are required.
- ///
- /// **Note**: Message contents must be under 2000 unicode code points.
- ///
- /// # Errors
- ///
- /// If the content of the message is over the above limit, then a
- /// [`ClientError::MessageTooLong`] will be returned, containing the number
- /// of unicode code points over the limit.
- ///
- /// [`ChannelId::send_files`]: struct.ChannelId.html#method.send_files
- /// [`ClientError::MessageTooLong`]: ../client/enum.ClientError.html#variant.MessageTooLong
- /// [Attach Files]: permissions/constant.ATTACH_FILES.html
- /// [Send Messages]: permissions/constant.SEND_MESSAGES.html
- #[inline]
- pub fn send_files<'a, F, T, It: IntoIterator<Item=T>>(&self, files: It, f: F) -> Result<Message>
- where F: FnOnce(CreateMessage) -> CreateMessage, T: Into<AttachmentType<'a>> {
- self.id.send_files(files, f)
- }
-
- /// Sends a message to the channel with the given content.
- ///
- /// Refer to the documentation for [`CreateMessage`] for more information
- /// regarding message restrictions and requirements.
- ///
- /// # Errors
- ///
- /// Returns a [`ModelError::MessageTooLong`] if the content of the message
- /// is over the above limit, containing the number of unicode code points
- /// over the limit.
- ///
- /// [`ModelError::MessageTooLong`]: enum.ModelError.html#variant.MessageTooLong
- /// [`CreateMessage`]: ../builder/struct.CreateMessage.html
- /// [`Message`]: struct.Message.html
- #[inline]
- pub fn send_message<F: FnOnce(CreateMessage) -> CreateMessage>(&self, f: F) -> Result<Message> {
- self.id.send_message(f)
- }
-
- /// Unpins a [`Message`] in the channel given by its Id.
- ///
- /// Requires the [Manage Messages] permission.
- ///
- /// [`Message`]: struct.Message.html
- /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
- #[inline]
- pub fn unpin<M: Into<MessageId>>(&self, message_id: M) -> Result<()> {
- self.id.unpin(message_id)
+ pub fn name(&self) -> String {
+ format!("DM with {}", self.recipient.borrow().tag())
}
}
impl Display for PrivateChannel {
/// Formats the private channel, displaying the recipient's username.
fn fmt(&self, f: &mut Formatter) -> FmtResult {
- f.write_str(&self.recipient.read().name)
+ f.write_str(&self.recipient.borrow().name)
}
}
diff --git a/src/model/channel/reaction.rs b/src/model/channel/reaction.rs
index fcffa20..d10d715 100644
--- a/src/model/channel/reaction.rs
+++ b/src/model/channel/reaction.rs
@@ -13,11 +13,6 @@ use std::{
};
use internal::prelude::*;
-#[cfg(all(feature = "cache", feature = "model"))]
-use CACHE;
-#[cfg(feature = "model")]
-use http;
-
/// An emoji reaction to a message.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Reaction {
@@ -38,135 +33,6 @@ pub struct Reaction {
pub user_id: UserId,
}
-#[cfg(feature = "model")]
-impl Reaction {
- /// Retrieves the associated the reaction was made in.
- ///
- /// If the cache is enabled, this will search for the already-cached
- /// channel. If not - or the channel was not found - this will perform a
- /// request over the REST API for the channel.
- ///
- /// Requires the [Read Message History] permission.
- ///
- /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
- #[inline]
- pub fn channel(&self) -> Result<Channel> {
- self.channel_id.get()
- }
-
- /// Deletes the reaction, but only if the current user is the user who made
- /// the reaction or has permission to.
- ///
- /// Requires the [Manage Messages] permission, _if_ the current
- /// user did not perform the reaction.
- ///
- /// # Errors
- ///
- /// If the `cache` is enabled, then returns a
- /// [`ModelError::InvalidPermissions`] if the current user does not have
- /// the required [permissions].
- ///
- /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
- /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
- /// [permissions]: permissions
- pub fn delete(&self) -> Result<()> {
- let user_id = feature_cache! {
- {
- let user = if self.user_id == CACHE.read().user.id {
- None
- } else {
- Some(self.user_id.0)
- };
-
- // If the reaction is one _not_ made by the current user, then ensure
- // that the current user has permission* to delete the reaction.
- //
- // Normally, users can only delete their own reactions.
- //
- // * The `Manage Messages` permission.
- if user.is_some() {
- let req = Permissions::MANAGE_MESSAGES;
-
- if !utils::user_has_perms(self.channel_id, req).unwrap_or(true) {
- return Err(Error::Model(ModelError::InvalidPermissions(req)));
- }
- }
-
- user
- } else {
- Some(self.user_id.0)
- }
- };
-
- http::delete_reaction(self.channel_id.0, self.message_id.0, user_id, &self.emoji)
- }
-
- /// Retrieves the [`Message`] associated with this reaction.
- ///
- /// Requires the [Read Message History] permission.
- ///
- /// **Note**: This will send a request to the REST API. Prefer maintaining
- /// your own message cache or otherwise having the message available if
- /// possible.
- ///
- /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
- /// [`Message`]: struct.Message.html
- #[inline]
- pub fn message(&self) -> Result<Message> {
- self.channel_id.message(self.message_id)
- }
-
- /// Retrieves the user that made the reaction.
- ///
- /// If the cache is enabled, this will search for the already-cached user.
- /// If not - or the user was not found - this will perform a request over
- /// the REST API for the user.
- #[inline]
- pub fn user(&self) -> Result<User> {
- self.user_id.get()
- }
-
- /// Retrieves the list of [`User`]s who have reacted to a [`Message`] with a
- /// certain [`Emoji`].
- ///
- /// The default `limit` is `50` - specify otherwise to receive a different
- /// maximum number of users. The maximum that may be retrieve at a time is
- /// `100`, if a greater number is provided then it is automatically reduced.
- ///
- /// The optional `after` attribute is to retrieve the users after a certain
- /// user. This is useful for pagination.
- ///
- /// Requires the [Read Message History] permission.
- ///
- /// **Note**: This will send a request to the REST API.
- ///
- /// # Errors
- ///
- /// Returns a [`ModelError::InvalidPermissions`] if the current user does
- /// not have the required [permissions].
- ///
- /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
- /// [`Emoji`]: struct.Emoji.html
- /// [`Message`]: struct.Message.html
- /// [`User`]: struct.User.html
- /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
- /// [permissions]: permissions
- pub fn users<R, U>(&self,
- reaction_type: R,
- limit: Option<u8>,
- after: Option<U>)
- -> Result<Vec<User>>
- where R: Into<ReactionType>, U: Into<UserId> {
- http::get_reaction_users(
- self.channel_id.0,
- self.message_id.0,
- &reaction_type.into(),
- limit.unwrap_or(50),
- after.map(|u| u.into().0),
- )
- }
-}
-
/// The type of a [`Reaction`] sent.
///
/// [`Reaction`]: struct.Reaction.html
@@ -307,7 +173,6 @@ impl ReactionType {
}
}
-#[cfg(feature = "model")]
impl From<char> for ReactionType {
/// Creates a `ReactionType` from a `char`.
///
diff --git a/src/model/error.rs b/src/model/error.rs
index c0cd609..bd877bf 100644
--- a/src/model/error.rs
+++ b/src/model/error.rs
@@ -79,6 +79,9 @@ pub enum Error {
/// When attempting to delete below or above the minimum and maximum allowed
/// number of messages.
BulkDeleteAmount,
+ /// The client wasn't present on the model when it was expected to be, e.g.
+ /// when performing a cache or HTTP operation on it.
+ ClientNotPresent,
/// When attempting to delete a number of days' worth of messages that is
/// not allowed.
DeleteMessageDaysAmount(u8),
@@ -137,6 +140,7 @@ impl StdError for Error {
fn description(&self) -> &str {
match *self {
Error::BulkDeleteAmount => "Too few/many messages to bulk delete",
+ Error::ClientNotPresent => "The client wasn't present on the model",
Error::DeleteMessageDaysAmount(_) => "Invalid delete message days",
Error::EmbedTooLarge(_) => "Embed too large",
Error::GuildNotFound => "Guild not found in the cache",
diff --git a/src/model/event.rs b/src/model/event.rs
index 093adcd..7922b23 100644
--- a/src/model/event.rs
+++ b/src/model/event.rs
@@ -14,15 +14,6 @@ use super::prelude::*;
use constants::{OpCode, VoiceOpCode};
use internal::prelude::*;
-#[cfg(feature = "cache")]
-use cache::{Cache, CacheUpdate};
-#[cfg(feature = "cache")]
-use internal::RwLockExt;
-#[cfg(feature = "cache")]
-use std::collections::hash_map::Entry;
-#[cfg(feature = "cache")]
-use std::mem;
-
/// Event data for the channel creation event.
///
/// This is fired when:
@@ -56,107 +47,11 @@ impl Serialize for ChannelCreateEvent {
}
}
-#[cfg(feature = "cache")]
-impl CacheUpdate for ChannelCreateEvent {
- type Output = Channel;
-
- fn update(&mut self, cache: &mut Cache) -> Option<Self::Output> {
- match self.channel {
- Channel::Group(ref group) => {
- let group = Arc::clone(group);
-
- let channel_id = group.with_mut(|writer| {
- for (recipient_id, recipient) in &mut writer.recipients {
- cache.update_user_entry(&recipient.read());
-
- *recipient = Arc::clone(&cache.users[recipient_id]);
- }
-
- writer.channel_id
- });
-
- let ch = cache.groups.insert(channel_id, group);
-
- ch.map(Channel::Group)
- },
- Channel::Guild(ref channel) => {
- let (guild_id, channel_id) = channel.with(|channel| (channel.guild_id, channel.id));
-
- cache.channels.insert(channel_id, Arc::clone(channel));
-
- cache
- .guilds
- .get_mut(&guild_id)
- .and_then(|guild| {
- guild
- .with_mut(|guild| guild.channels.insert(channel_id, Arc::clone(channel)))
- })
- .map(Channel::Guild)
- },
- Channel::Private(ref channel) => {
- if let Some(channel) = cache.private_channels.get(&channel.with(|c| c.id)) {
- return Some(Channel::Private(Arc::clone(&(*channel))));
- }
-
- let channel = Arc::clone(channel);
-
- let id = channel.with_mut(|writer| {
- let user_id = writer.recipient.with_mut(|user| {
- cache.update_user_entry(user);
-
- user.id
- });
-
- writer.recipient = Arc::clone(&cache.users[&user_id]);
- writer.id
- });
-
- let ch = cache.private_channels.insert(id, Arc::clone(&channel));
- ch.map(Channel::Private)
- },
- Channel::Category(ref category) => cache
- .categories
- .insert(category.read().id, Arc::clone(category))
- .map(Channel::Category),
- }
- }
-}
-
#[derive(Clone, Debug)]
pub struct ChannelDeleteEvent {
pub channel: Channel,
}
-#[cfg(feature = "cache")]
-impl CacheUpdate for ChannelDeleteEvent {
- type Output = ();
-
- fn update(&mut self, cache: &mut Cache) -> Option<()> {
- match self.channel {
- Channel::Guild(ref channel) => {
- let (guild_id, channel_id) = channel.with(|channel| (channel.guild_id, channel.id));
-
- cache.channels.remove(&channel_id);
-
- cache
- .guilds
- .get_mut(&guild_id)
- .and_then(|guild| guild.with_mut(|g| g.channels.remove(&channel_id)));
- },
- Channel::Category(ref category) => {
- let channel_id = category.with(|cat| cat.id);
-
- cache.categories.remove(&channel_id);
- },
- // We ignore these two due to the fact that the delete event for dms/groups
- // will _not_ fire anymore.
- Channel::Private(_) | Channel::Group(_) => unreachable!(),
- };
-
- None
- }
-}
-
impl<'de> Deserialize<'de> for ChannelDeleteEvent {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
Ok(Self {
@@ -178,143 +73,23 @@ pub struct ChannelPinsUpdateEvent {
pub last_pin_timestamp: Option<DateTime<FixedOffset>>,
}
-#[cfg(feature = "cache")]
-impl CacheUpdate for ChannelPinsUpdateEvent {
- type Output = ();
-
- fn update(&mut self, cache: &mut Cache) -> Option<()> {
- if let Some(channel) = cache.channels.get(&self.channel_id) {
- channel.with_mut(|c| {
- c.last_pin_timestamp = self.last_pin_timestamp;
- });
-
- return None;
- }
-
- if let Some(channel) = cache.private_channels.get_mut(&self.channel_id) {
- channel.with_mut(|c| {
- c.last_pin_timestamp = self.last_pin_timestamp;
- });
-
- return None;
- }
-
- if let Some(group) = cache.groups.get_mut(&self.channel_id) {
- group.with_mut(|c| {
- c.last_pin_timestamp = self.last_pin_timestamp;
- });
-
- return None;
- }
-
- None
- }
-}
-
-
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ChannelRecipientAddEvent {
pub channel_id: ChannelId,
pub user: User,
}
-#[cfg(feature = "cache")]
-impl CacheUpdate for ChannelRecipientAddEvent {
- type Output = ();
-
- fn update(&mut self, cache: &mut Cache) -> Option<()> {
- cache.update_user_entry(&self.user);
- let user = Arc::clone(&cache.users[&self.user.id]);
-
- cache.groups.get_mut(&self.channel_id).map(|group| {
- group.write().recipients.insert(self.user.id, user);
- });
-
- None
- }
-}
-
-
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ChannelRecipientRemoveEvent {
pub channel_id: ChannelId,
pub user: User,
}
-#[cfg(feature = "cache")]
-impl CacheUpdate for ChannelRecipientRemoveEvent {
- type Output = ();
-
- fn update(&mut self, cache: &mut Cache) -> Option<()> {
- cache.groups.get_mut(&self.channel_id).map(|group| {
- group.with_mut(|g| g.recipients.remove(&self.user.id))
- });
-
- None
- }
-}
-
#[derive(Clone, Debug)]
pub struct ChannelUpdateEvent {
pub channel: Channel,
}
-#[cfg(feature = "cache")]
-impl CacheUpdate for ChannelUpdateEvent {
- type Output = ();
-
- fn update(&mut self, cache: &mut Cache) -> Option<()> {
- match self.channel {
- Channel::Group(ref group) => {
- let (ch_id, no_recipients) =
- group.with(|g| (g.channel_id, g.recipients.is_empty()));
-
- match cache.groups.entry(ch_id) {
- Entry::Vacant(e) => {
- e.insert(Arc::clone(group));
- },
- Entry::Occupied(mut e) => {
- let mut dest = e.get_mut().write();
-
- if no_recipients {
- let recipients = mem::replace(&mut dest.recipients, HashMap::new());
-
- dest.clone_from(&group.read());
-
- dest.recipients = recipients;
- } else {
- dest.clone_from(&group.read());
- }
- },
- }
- },
- Channel::Guild(ref channel) => {
- let (guild_id, channel_id) = channel.with(|channel| (channel.guild_id, channel.id));
-
- cache.channels.insert(channel_id, Arc::clone(channel));
- cache.guilds.get_mut(&guild_id).map(|guild| {
- guild
- .with_mut(|g| g.channels.insert(channel_id, Arc::clone(channel)))
- });
- },
- Channel::Private(ref channel) => {
- cache
- .private_channels
- .get_mut(&channel.read().id)
- .map(|private| private.clone_from(channel));
- },
- Channel::Category(ref category) => {
- cache
- .categories
- .get_mut(&category.read().id)
- .map(|c| c.clone_from(category));
- },
- }
-
- None
- }
-}
-
impl<'de> Deserialize<'de> for ChannelUpdateEvent {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
Ok(Self {
@@ -347,31 +122,6 @@ pub struct GuildCreateEvent {
pub guild: Guild,
}
-#[cfg(feature = "cache")]
-impl CacheUpdate for GuildCreateEvent {
- type Output = ();
-
- fn update(&mut self, cache: &mut Cache) -> Option<()> {
- cache.unavailable_guilds.remove(&self.guild.id);
-
- let mut guild = self.guild.clone();
-
- for (user_id, member) in &mut guild.members {
- cache.update_user_entry(&member.user.read());
- let user = Arc::clone(&cache.users[user_id]);
-
- member.user = Arc::clone(&user);
- }
-
- cache.channels.extend(guild.channels.clone());
- cache
- .guilds
- .insert(self.guild.id, Arc::new(RwLock::new(guild)));
-
- None
- }
-}
-
impl<'de> Deserialize<'de> for GuildCreateEvent {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
Ok(Self {
@@ -392,22 +142,6 @@ pub struct GuildDeleteEvent {
pub guild: PartialGuild,
}
-#[cfg(feature = "cache")]
-impl CacheUpdate for GuildDeleteEvent {
- type Output = Arc<RwLock<Guild>>;
-
- fn update(&mut self, cache: &mut Cache) -> Option<Self::Output> {
- // Remove channel entries for the guild if the guild is found.
- cache.guilds.remove(&self.guild.id).map(|guild| {
- for channel_id in guild.write().channels.keys() {
- cache.channels.remove(channel_id);
- }
-
- guild
- })
- }
-}
-
impl<'de> Deserialize<'de> for GuildDeleteEvent {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
Ok(Self {
@@ -429,21 +163,6 @@ pub struct GuildEmojisUpdateEvent {
pub guild_id: GuildId,
}
-#[cfg(feature = "cache")]
-impl CacheUpdate for GuildEmojisUpdateEvent {
- type Output = ();
-
- fn update(&mut self, cache: &mut Cache) -> Option<()> {
- cache.guilds.get_mut(&self.guild_id).map(|guild| {
- guild.with_mut(|g| {
- g.emojis.clone_from(&self.emojis)
- });
- });
-
- None
- }
-}
-
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct GuildIntegrationsUpdateEvent {
pub guild_id: GuildId,
@@ -455,28 +174,6 @@ pub struct GuildMemberAddEvent {
pub member: Member,
}
-#[cfg(feature = "cache")]
-impl CacheUpdate for GuildMemberAddEvent {
- type Output = ();
-
- fn update(&mut self, cache: &mut Cache) -> Option<()> {
- let user_id = self.member.user.with(|u| u.id);
- cache.update_user_entry(&self.member.user.read());
-
- // Always safe due to being inserted above.
- self.member.user = Arc::clone(&cache.users[&user_id]);
-
- cache.guilds.get_mut(&self.guild_id).map(|guild| {
- guild.with_mut(|guild| {
- guild.member_count += 1;
- guild.members.insert(user_id, self.member.clone());
- })
- });
-
- None
- }
-}
-
impl<'de> Deserialize<'de> for GuildMemberAddEvent {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
let map = JsonMap::deserialize(deserializer)?;
@@ -500,20 +197,6 @@ pub struct GuildMemberRemoveEvent {
pub user: User,
}
-#[cfg(feature = "cache")]
-impl CacheUpdate for GuildMemberRemoveEvent {
- type Output = Member;
-
- fn update(&mut self, cache: &mut Cache) -> Option<Self::Output> {
- cache.guilds.get_mut(&self.guild_id).and_then(|guild| {
- guild.with_mut(|guild| {
- guild.member_count -= 1;
- guild.members.remove(&self.user.id)
- })
- })
- }
-}
-
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct GuildMemberUpdateEvent {
pub guild_id: GuildId,
@@ -522,77 +205,12 @@ pub struct GuildMemberUpdateEvent {
pub user: User,
}
-#[cfg(feature = "cache")]
-impl CacheUpdate for GuildMemberUpdateEvent {
- type Output = Member;
-
- fn update(&mut self, cache: &mut Cache) -> Option<Self::Output> {
- cache.update_user_entry(&self.user);
-
- if let Some(guild) = cache.guilds.get_mut(&self.guild_id) {
- let mut guild = guild.write();
-
- let mut found = false;
-
- let item = if let Some(member) = guild.members.get_mut(&self.user.id) {
- let item = Some(member.clone());
-
- member.nick.clone_from(&self.nick);
- member.roles.clone_from(&self.roles);
- member.user.write().clone_from(&self.user);
-
- found = true;
-
- item
- } else {
- None
- };
-
- if !found {
- guild.members.insert(
- self.user.id,
- Member {
- deaf: false,
- guild_id: self.guild_id,
- joined_at: None,
- mute: false,
- nick: self.nick.clone(),
- roles: self.roles.clone(),
- user: Arc::new(RwLock::new(self.user.clone())),
- },
- );
- }
-
- item
- } else {
- None
- }
- }
-}
-
#[derive(Clone, Debug, Serialize)]
pub struct GuildMembersChunkEvent {
pub guild_id: GuildId,
pub members: HashMap<UserId, Member>,
}
-#[cfg(feature = "cache")]
-impl CacheUpdate for GuildMembersChunkEvent {
- type Output = ();
-
- fn update(&mut self, cache: &mut Cache) -> Option<()> {
- for member in self.members.values() {
- cache.update_user_entry(&member.user.read());
- }
-
- cache.guilds.get_mut(&self.guild_id).map(|guild| {
- guild.with_mut(|g| g.members.extend(self.members.clone()))
- });
-
- None
- }
-}
-
impl<'de> Deserialize<'de> for GuildMembersChunkEvent {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
let mut map = JsonMap::deserialize(deserializer)?;
@@ -619,9 +237,11 @@ impl<'de> Deserialize<'de> for GuildMembersChunkEvent {
.map(|members| members
.into_iter()
.fold(HashMap::new(), |mut acc, member| {
- let id = member.user.read().id;
+ let id = member.user.try_borrow().ok().map(|u| u.id);
- acc.insert(id, member);
+ if let Some(id) = id {
+ acc.insert(id, member);
+ }
acc
}))
@@ -640,105 +260,28 @@ pub struct GuildRoleCreateEvent {
pub role: Role,
}
-#[cfg(feature = "cache")]
-impl CacheUpdate for GuildRoleCreateEvent {
- type Output = ();
-
- fn update(&mut self, cache: &mut Cache) -> Option<()> {
- cache.guilds.get_mut(&self.guild_id).map(|guild| {
- guild
- .write()
- .roles
- .insert(self.role.id, self.role.clone())
- });
-
- None
- }
-}
-
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct GuildRoleDeleteEvent {
pub guild_id: GuildId,
pub role_id: RoleId,
}
-#[cfg(feature = "cache")]
-impl CacheUpdate for GuildRoleDeleteEvent {
- type Output = Role;
-
- fn update(&mut self, cache: &mut Cache) -> Option<Self::Output> {
- cache
- .guilds
- .get_mut(&self.guild_id)
- .and_then(|guild| guild.with_mut(|g| g.roles.remove(&self.role_id)))
- }
-}
-
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct GuildRoleUpdateEvent {
pub guild_id: GuildId,
pub role: Role,
}
-#[cfg(feature = "cache")]
-impl CacheUpdate for GuildRoleUpdateEvent {
- type Output = Role;
-
- fn update(&mut self, cache: &mut Cache) -> Option<Self::Output> {
- cache.guilds.get_mut(&self.guild_id).and_then(|guild| {
- guild.with_mut(|g| {
- g.roles
- .get_mut(&self.role.id)
- .map(|role| mem::replace(role, self.role.clone()))
- })
- })
- }
-}
-
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct GuildUnavailableEvent {
#[serde(rename = "id")] pub guild_id: GuildId,
}
-#[cfg(feature = "cache")]
-impl CacheUpdate for GuildUnavailableEvent {
- type Output = ();
-
- fn update(&mut self, cache: &mut Cache) -> Option<()> {
- cache.unavailable_guilds.insert(self.guild_id);
- cache.guilds.remove(&self.guild_id);
-
- None
- }
-}
-
#[derive(Clone, Debug)]
pub struct GuildUpdateEvent {
pub guild: PartialGuild,
}
-#[cfg(feature = "cache")]
-impl CacheUpdate for GuildUpdateEvent {
- type Output = ();
-
- fn update(&mut self, cache: &mut Cache) -> Option<()> {
- cache.guilds.get_mut(&self.guild.id).map(|guild| {
- let mut guild = guild.write();
-
- guild.afk_timeout = self.guild.afk_timeout;
- guild.afk_channel_id.clone_from(&self.guild.afk_channel_id);
- guild.icon.clone_from(&self.guild.icon);
- guild.name.clone_from(&self.guild.name);
- guild.owner_id.clone_from(&self.guild.owner_id);
- guild.region.clone_from(&self.guild.region);
- guild.roles.clone_from(&self.guild.roles);
- guild.verification_level = self.guild.verification_level;
- });
-
- None
- }
-}
-
impl<'de> Deserialize<'de> for GuildUpdateEvent {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
Ok(Self {
@@ -802,7 +345,7 @@ pub struct MessageUpdateEvent {
pub mentions: Option<Vec<User>>,
pub mention_roles: Option<Vec<RoleId>>,
pub attachments: Option<Vec<Attachment>>,
- pub embeds: Option<Vec<Value>>,
+ pub embeds: Option<Vec<Embed>>,
}
#[derive(Clone, Debug, Serialize)]
@@ -812,62 +355,6 @@ pub struct PresenceUpdateEvent {
pub roles: Option<Vec<RoleId>>,
}
-#[cfg(feature = "cache")]
-impl CacheUpdate for PresenceUpdateEvent {
- type Output = ();
-
- fn update(&mut self, cache: &mut Cache) -> Option<()> {
- let user_id = self.presence.user_id;
-
- if let Some(user) = self.presence.user.as_mut() {
- cache.update_user_entry(&user.read());
- *user = Arc::clone(&cache.users[&user_id]);
- }
-
- if let Some(guild_id) = self.guild_id {
- if let Some(guild) = cache.guilds.get_mut(&guild_id) {
- let mut guild = guild.write();
-
- // If the member went offline, remove them from the presence list.
- if self.presence.status == OnlineStatus::Offline {
- guild.presences.remove(&self.presence.user_id);
- } else {
- guild
- .presences
- .insert(self.presence.user_id, self.presence.clone());
- }
-
- // Create a partial member instance out of the presence update
- // data. This includes everything but `deaf`, `mute`, and
- // `joined_at`.
- if !guild.members.contains_key(&self.presence.user_id) {
- if let Some(user) = self.presence.user.as_ref() {
- let roles = self.roles.clone().unwrap_or_default();
-
- guild.members.insert(self.presence.user_id, Member {
- deaf: false,
- guild_id,
- joined_at: None,
- mute: false,
- nick: self.presence.nick.clone(),
- user: Arc::clone(&user),
- roles,
- });
- }
- }
- }
- } else if self.presence.status == OnlineStatus::Offline {
- cache.presences.remove(&self.presence.user_id);
- } else {
- cache
- .presences
- .insert(self.presence.user_id, self.presence.clone());
- }
-
- None
- }
-}
-
impl<'de> Deserialize<'de> for PresenceUpdateEvent {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
let mut map = JsonMap::deserialize(deserializer)?;
@@ -898,25 +385,6 @@ pub struct PresencesReplaceEvent {
pub presences: Vec<Presence>,
}
-#[cfg(feature = "cache")]
-impl CacheUpdate for PresencesReplaceEvent {
- type Output = ();
-
- fn update(&mut self, cache: &mut Cache) -> Option<()> {
- cache.presences.extend({
- let mut p: HashMap<UserId, Presence> = HashMap::default();
-
- for presence in &self.presences {
- p.insert(presence.user_id, presence.clone());
- }
-
- p
- });
-
- None
- }
-}
-
impl<'de> Deserialize<'de> for PresencesReplaceEvent {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
let presences: Vec<Presence> = Deserialize::deserialize(deserializer)?;
@@ -992,46 +460,6 @@ pub struct ReadyEvent {
pub ready: Ready,
}
-#[cfg(feature = "cache")]
-impl CacheUpdate for ReadyEvent {
- type Output = ();
-
- fn update(&mut self, cache: &mut Cache) -> Option<()> {
- let mut ready = self.ready.clone();
-
- for guild in ready.guilds {
- match guild {
- GuildStatus::Offline(unavailable) => {
- cache.guilds.remove(&unavailable.id);
- cache.unavailable_guilds.insert(unavailable.id);
- },
- GuildStatus::OnlineGuild(guild) => {
- cache.unavailable_guilds.remove(&guild.id);
- cache.guilds.insert(guild.id, Arc::new(RwLock::new(guild)));
- },
- GuildStatus::OnlinePartialGuild(_) => {},
- }
- }
-
- // `ready.private_channels` will always be empty, and possibly be removed in the future.
- // So don't handle it at all.
-
- for (user_id, presence) in &mut ready.presences {
- if let Some(ref user) = presence.user {
- cache.update_user_entry(&user.read());
- }
-
- presence.user = cache.users.get(user_id).cloned();
- }
-
- cache.presences.extend(ready.presences);
- cache.shard_count = ready.shard.map_or(1, |s| s[1]);
- cache.user = ready.user;
-
- None
- }
-}
-
impl<'de> Deserialize<'de> for ReadyEvent {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
Ok(Self {
@@ -1070,15 +498,6 @@ pub struct UserUpdateEvent {
pub current_user: CurrentUser,
}
-#[cfg(feature = "cache")]
-impl CacheUpdate for UserUpdateEvent {
- type Output = CurrentUser;
-
- fn update(&mut self, cache: &mut Cache) -> Option<Self::Output> {
- Some(mem::replace(&mut cache.user, self.current_user.clone()))
- }
-}
-
impl<'de> Deserialize<'de> for UserUpdateEvent {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
Ok(Self {
@@ -1108,43 +527,6 @@ pub struct VoiceStateUpdateEvent {
pub voice_state: VoiceState,
}
-#[cfg(feature = "cache")]
-impl CacheUpdate for VoiceStateUpdateEvent {
- type Output = ();
-
- fn update(&mut self, cache: &mut Cache) -> Option<()> {
- if let Some(guild_id) = self.guild_id {
- if let Some(guild) = cache.guilds.get_mut(&guild_id) {
- let mut guild = guild.write();
-
- if self.voice_state.channel_id.is_some() {
- // Update or add to the voice state list
- {
- let finding = guild.voice_states.get_mut(&self.voice_state.user_id);
-
- if let Some(srv_state) = finding {
- srv_state.clone_from(&self.voice_state);
-
- return None;
- }
- }
-
- guild
- .voice_states
- .insert(self.voice_state.user_id, self.voice_state.clone());
- } else {
- // Remove the user from the voice state list
- guild.voice_states.remove(&self.voice_state.user_id);
- }
- }
-
- return None;
- }
-
- None
- }
-}
-
impl<'de> Deserialize<'de> for VoiceStateUpdateEvent {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
let map = JsonMap::deserialize(deserializer)?;
diff --git a/src/model/gateway.rs b/src/model/gateway.rs
index 385902a..f1916f8 100644
--- a/src/model/gateway.rs
+++ b/src/model/gateway.rs
@@ -1,11 +1,11 @@
//! Models pertaining to the gateway.
use chrono::{DateTime, Utc};
-use parking_lot::RwLock;
use serde::de::Error as DeError;
use serde::ser::{SerializeStruct, Serialize, Serializer};
use serde_json;
-use std::sync::Arc;
+use std::cell::RefCell;
+use std::rc::Rc;
use super::utils::*;
use super::prelude::*;
@@ -57,7 +57,6 @@ pub struct Activity {
pub url: Option<String>,
}
-#[cfg(feature = "model")]
impl Activity {
/// Creates a `Game` struct that appears as a `Playing <name>` status.
///
@@ -360,7 +359,7 @@ pub struct Presence {
/// date.
pub user_id: UserId,
/// The associated user instance.
- pub user: Option<Arc<RwLock<User>>>,
+ pub user: Option<Rc<RefCell<User>>>,
}
impl<'de> Deserialize<'de> for Presence {
@@ -375,7 +374,7 @@ impl<'de> Deserialize<'de> for Presence {
let user = User::deserialize(Value::Object(user_map))
.map_err(DeError::custom)?;
- (user.id, Some(Arc::new(RwLock::new(user))))
+ (user.id, Some(Rc::new(RefCell::new(user))))
} else {
let user_id = user_map
.remove("id")
@@ -431,7 +430,7 @@ impl Serialize for Presence {
state.serialize_field("status", &self.status)?;
if let Some(ref user) = self.user {
- state.serialize_field("user", &*user.read())?;
+ state.serialize_field("user", &*user.borrow())?;
} else {
state.serialize_field("user", &UserId {
id: self.user_id.0,
@@ -446,10 +445,14 @@ impl Serialize for Presence {
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Ready {
pub guilds: Vec<GuildStatus>,
- #[serde(default, deserialize_with = "deserialize_presences")]
- pub presences: HashMap<UserId, Presence>,
- #[serde(default, deserialize_with = "deserialize_private_channels")]
- pub private_channels: HashMap<ChannelId, Channel>,
+ #[serde(default,
+ deserialize_with = "deserialize_presences",
+ serialize_with = "serialize_gen_rc_map")]
+ pub presences: HashMap<UserId, Rc<RefCell<Presence>>>,
+ #[serde(default,
+ deserialize_with = "deserialize_private_channels",
+ serialize_with = "serialize_gen_rc_map")]
+ pub private_channels: HashMap<ChannelId, Rc<RefCell<Channel>>>,
pub session_id: String,
pub shard: Option<[u64; 2]>,
#[serde(default, rename = "_trace")]
diff --git a/src/model/guild/emoji.rs b/src/model/guild/emoji.rs
index b2eb036..aca0153 100644
--- a/src/model/guild/emoji.rs
+++ b/src/model/guild/emoji.rs
@@ -1,22 +1,11 @@
use std::fmt::{
- Display,
- Formatter,
- Result as FmtResult,
+ Display,
+ Formatter,
+ Result as FmtResult,
Write as FmtWrite
};
use super::super::id::{EmojiId, RoleId};
-#[cfg(all(feature = "cache", feature = "model"))]
-use internal::prelude::*;
-#[cfg(all(feature = "cache", feature = "model"))]
-use std::mem;
-#[cfg(all(feature = "cache", feature = "model"))]
-use super::super::ModelError;
-#[cfg(all(feature = "cache", feature = "model"))]
-use super::super::id::GuildId;
-#[cfg(all(feature = "cache", feature = "model"))]
-use {CACHE, http};
-
/// Represents a custom guild emoji, which can either be created using the API,
/// or via an integration. Emojis created using the API only work within the
/// guild it was created in.
@@ -44,132 +33,7 @@ pub struct Emoji {
pub roles: Vec<RoleId>,
}
-#[cfg(feature = "model")]
impl Emoji {
- /// Deletes the emoji.
- ///
- /// **Note**: The [Manage Emojis] permission is required.
- ///
- /// [Manage Emojis]: permissions/constant.MANAGE_EMOJIS.html
- ///
- /// # Examples
- ///
- /// Delete a given emoji:
- ///
- /// ```rust,no_run
- /// # use serenity::model::guild::Emoji;
- /// # use serenity::model::id::EmojiId;
- /// #
- /// # let mut emoji = Emoji {
- /// # animated: false,
- /// # id: EmojiId(7),
- /// # name: String::from("blobface"),
- /// # managed: false,
- /// # require_colons: false,
- /// # roles: vec![],
- /// # };
- /// #
- /// // assuming emoji has been set already
- /// match emoji.delete() {
- /// Ok(()) => println!("Emoji deleted."),
- /// Err(_) => println!("Could not delete emoji.")
- /// }
- /// ```
- #[cfg(feature = "cache")]
- pub fn delete(&self) -> Result<()> {
- match self.find_guild_id() {
- Some(guild_id) => http::delete_emoji(guild_id.0, self.id.0),
- None => Err(Error::Model(ModelError::ItemMissing)),
- }
- }
-
- /// Edits the emoji by updating it with a new name.
- ///
- /// **Note**: The [Manage Emojis] permission is required.
- ///
- /// [Manage Emojis]: permissions/constant.MANAGE_EMOJIS.html
- ///
- /// # Examples
- ///
- /// Change the name of an emoji:
- ///
- /// ```rust,no_run
- /// # use serenity::model::guild::Emoji;
- /// # use serenity::model::id::EmojiId;
- /// #
- /// # let mut emoji = Emoji {
- /// # animated: false,
- /// # id: EmojiId(7),
- /// # name: String::from("blobface"),
- /// # managed: false,
- /// # require_colons: false,
- /// # roles: vec![],
- /// # };
- /// #
- /// // assuming emoji has been set already
- /// let _ = emoji.edit("blobuwu");
- /// assert_eq!(emoji.name, "blobuwu");
- /// ```
- #[cfg(feature = "cache")]
- pub fn edit(&mut self, name: &str) -> Result<()> {
- match self.find_guild_id() {
- Some(guild_id) => {
- let map = json!({
- "name": name,
- });
-
- match http::edit_emoji(guild_id.0, self.id.0, &map) {
- Ok(emoji) => {
- mem::replace(self, emoji);
-
- Ok(())
- },
- Err(why) => Err(why),
- }
- },
- None => Err(Error::Model(ModelError::ItemMissing)),
- }
- }
-
- /// Finds the [`Guild`] that owns the emoji by looking through the Cache.
- ///
- /// [`Guild`]: struct.Guild.html
- ///
- /// # Examples
- ///
- /// Print the guild id that owns this emoji:
- ///
- /// ```rust,no_run
- /// # use serenity::model::guild::Emoji;
- /// # use serenity::model::id::EmojiId;
- /// #
- /// # let mut emoji = Emoji {
- /// # animated: false,
- /// # id: EmojiId(7),
- /// # name: String::from("blobface"),
- /// # managed: false,
- /// # require_colons: false,
- /// # roles: vec![],
- /// # };
- /// #
- /// // assuming emoji has been set already
- /// if let Some(guild_id) = emoji.find_guild_id() {
- /// println!("{} is owned by {}", emoji.name, guild_id);
- /// }
- /// ```
- #[cfg(feature = "cache")]
- pub fn find_guild_id(&self) -> Option<GuildId> {
- for guild in CACHE.read().guilds.values() {
- let guild = guild.read();
-
- if guild.emojis.contains_key(&self.id) {
- return Some(guild.id);
- }
- }
-
- None
- }
-
/// Generates a URL to the emoji's image.
///
/// # Examples
diff --git a/src/model/guild/guild_id.rs b/src/model/guild/guild_id.rs
index c07a40f..eacf07e 100644
--- a/src/model/guild/guild_id.rs
+++ b/src/model/guild/guild_id.rs
@@ -1,476 +1,15 @@
use model::prelude::*;
-#[cfg(all(feature = "cache", feature = "model"))]
-use CACHE;
-#[cfg(feature = "model")]
-use builder::{EditGuild, EditMember, EditRole};
-#[cfg(feature = "model")]
-use internal::prelude::*;
-#[cfg(feature = "model")]
-use model::guild::BanOptions;
-#[cfg(feature = "model")]
-use {http, utils};
-
-#[cfg(feature = "model")]
impl GuildId {
/// Converts the guild Id into the default channel's Id.
#[inline]
#[deprecated(note = "The concept of default channels is no more, use \
`Guild::default_channel{_guaranteed}` to simulate the
concept.")]
- pub fn as_channel_id(&self) -> ChannelId { ChannelId(self.0) }
-
- /// 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 [`ModelError::DeleteMessageDaysAmount`] if the number of
- /// days' worth of messages to delete is over the maximum.
- ///
- /// [`ModelError::DeleteMessageDaysAmount`]:
- /// enum.ModelError.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, BO>(&self, user: U, ban_options: &BO) -> Result<()>
- where U: Into<UserId>, BO: BanOptions {
- let dmd = ban_options.dmd();
- if dmd > 7 {
- return Err(Error::Model(ModelError::DeleteMessageDaysAmount(dmd)));
- }
-
- let reason = ban_options.reason();
-
- if reason.len() > 512 {
- return Err(Error::ExceededLimit(reason.to_string(), 512));
- }
-
- http::ban_user(self.0, user.into().0, dmd, &*reason)
- }
-
- /// Gets a list of the guild's bans.
- ///
- /// Requires the [Ban Members] permission.
- ///
- /// [Ban Members]: permissions/constant.BAN_MEMBERS.html
- #[inline]
- pub fn bans(&self) -> Result<Vec<Ban>> { http::get_bans(self.0) }
-
- /// Gets a list of the guild's audit log entries
- #[inline]
- pub fn audit_logs(&self, action_type: Option<u8>,
- user_id: Option<UserId>,
- before: Option<AuditLogEntryId>,
- limit: Option<u8>) -> Result<AuditLogs> {
- http::get_audit_logs(self.0, action_type, user_id.map(|u| u.0), before.map(|a| a.0), limit)
- }
-
- /// Gets all of the guild's channels over the REST API.
- ///
- /// [`Guild`]: struct.Guild.html
- pub fn channels(&self) -> Result<HashMap<ChannelId, GuildChannel>> {
- let mut channels = HashMap::new();
-
- for channel in http::get_channels(self.0)? {
- channels.insert(channel.id, channel);
- }
-
- Ok(channels)
- }
-
- /// Creates a [`GuildChannel`] in the the guild.
- ///
- /// Refer to [`http::create_channel`] for more information.
- ///
- /// Requires the [Manage Channels] permission.
- ///
- /// # Examples
- ///
- /// Create a voice channel in a guild with the name `test`:
- ///
- /// ```rust,ignore
- /// use serenity::model::{ChannelType, GuildId};
- ///
- /// let _channel = GuildId(7).create_channel("test", ChannelType::Voice, None);
- /// ```
- ///
- /// [`GuildChannel`]: struct.GuildChannel.html
- /// [`http::create_channel`]: ../http/fn.create_channel.html
- /// [Manage Channels]: permissions/constant.MANAGE_CHANNELS.html
- pub fn create_channel<C>(&self, name: &str, kind: ChannelType, category: C) -> Result<GuildChannel>
- where C: Into<Option<ChannelId>> {
- let map = json!({
- "name": name,
- "type": kind as u8,
- "parent_id": category.into().map(|c| c.0)
- });
-
- http::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`]: ../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 = json!({
- "name": name,
- "image": image,
- });
-
- http::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 = json!({
- "id": integration_id.0,
- "type": kind,
- });
-
- http::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/constant.MANAGE_ROLES.html
- #[inline]
- pub fn create_role<F: FnOnce(EditRole) -> EditRole>(&self, f: F) -> Result<Role> {
- let map = utils::vecmap_to_json_map(f(EditRole::default()).0);
-
- let role = http::create_role(self.0, &map)?;
-
- if let Some(position) = map.get("position").and_then(Value::as_u64) {
- self.edit_role_position(role.id, position)?;
- }
-
- Ok(role)
+ pub fn as_channel_id(&self) -> ChannelId {
+ ChannelId(self.0)
}
- /// 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> { http::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<()> {
- http::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<()> {
- http::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<()> {
- http::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/constant.MANAGE_GUILD.html
- #[inline]
- pub fn edit<F: FnOnce(EditGuild) -> EditGuild>(&mut self, f: F) -> Result<PartialGuild> {
- let map = utils::vecmap_to_json_map(f(EditGuild::default()).0);
-
- http::edit_guild(self.0, &map)
- }
-
- /// 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 = json!({
- "name": name,
- });
-
- http::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> {
- let map = utils::vecmap_to_json_map(f(EditMember::default()).0);
-
- http::edit_member(self.0, user_id.into().0, &map)
- }
-
- /// 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<()> {
- http::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> {
- let map = utils::vecmap_to_json_map(f(EditRole::default()).0);
-
- http::edit_role(self.0, role_id.into().0, &map)
- }
-
- /// Edits the order of [`Role`]s
- /// Requires the [Manage Roles] permission.
- ///
- /// # Examples
- ///
- /// Change the order of a role:
- ///
- /// ```rust,ignore
- /// use serenity::model::{GuildId, RoleId};
- /// GuildId(7).edit_role_position(RoleId(8), 2);
- /// ```
- ///
- /// [`Role`]: struct.Role.html
- /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
- #[inline]
- pub fn edit_role_position<R>(&self, role_id: R, position: u64) -> Result<Vec<Role>>
- where R: Into<RoleId> {
- http::edit_role_position(self.0, role_id.into().0, position)
- }
-
-
- /// Search the cache for the guild.
- #[cfg(feature = "cache")]
- pub fn find(&self) -> Option<Arc<RwLock<Guild>>> { CACHE.read().guild(*self) }
-
- /// 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> { http::get_guild(self.0) }
-
- /// Gets all integration of the guild.
- ///
- /// This performs a request over the REST API.
- #[inline]
- pub fn integrations(&self) -> Result<Vec<Integration>> { http::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 invites(&self) -> Result<Vec<RichInvite>> { http::get_guild_invites(self.0) }
-
- /// 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<()> {
- http::kick_member(self.0, user_id.into().0)
- }
-
- /// Leaves the guild.
- #[inline]
- pub fn leave(&self) -> Result<()> { http::leave_guild(self.0) }
-
- /// Gets a user's [`Member`] for the guild by Id.
- ///
- /// [`Guild`]: struct.Guild.html
- /// [`Member`]: struct.Member.html
- #[inline]
- pub fn member<U: Into<UserId>>(&self, user_id: U) -> Result<Member> {
- http::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 members<U>(&self, limit: Option<u64>, after: Option<U>) -> Result<Vec<Member>>
- where U: Into<UserId> {
- http::get_guild_members(self.0, limit, after.map(|x| x.into().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 mut map = Map::new();
- map.insert(
- "channel_id".to_string(),
- Value::Number(Number::from(channel_id.into().0)),
- );
-
- http::edit_member(self.0, user_id.into().0, &map)
- }
-
- /// 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 prune_count(&self, days: u16) -> Result<GuildPrune> {
- let map = json!({
- "days": days,
- });
-
- http::get_guild_prune_count(self.0, &map)
- }
-
- /// Re-orders the channels of the guild.
- ///
- /// Accepts an iterator of a tuple of the channel ID to modify and its new
- /// position.
- ///
- /// Although not required, you should specify all channels' positions,
- /// regardless of whether they were updated. Otherwise, positioning can
- /// sometimes get weird.
- pub fn reorder_channels<It>(&self, channels: It) -> Result<()>
- where It: IntoIterator<Item = (ChannelId, u64)> {
- let items = channels.into_iter().map(|(id, pos)| json!({
- "id": id,
- "position": pos,
- })).collect();
-
- http::edit_guild_channel_positions(self.0, &Value::Array(items))
- }
-
- /// Returns the Id of the shard associated with the guild.
- ///
- /// When the cache is enabled this will automatically retrieve the total
- /// number of shards.
- ///
- /// **Note**: When the cache is enabled, this function unlocks the cache to
- /// retrieve the total number of shards in use. If you already have the
- /// total, consider using [`utils::shard_id`].
- ///
- /// [`utils::shard_id`]: ../utils/fn.shard_id.html
- #[cfg(all(feature = "cache", feature = "utils"))]
- #[inline]
- pub fn shard_id(&self) -> u64 { ::utils::shard_id(self.0, CACHE.read().shard_count) }
-
/// Returns the Id of the shard associated with the guild.
///
/// When the cache is enabled this will automatically retrieve the total
@@ -492,66 +31,11 @@ impl GuildId {
///
/// assert_eq!(guild_id.shard_id(17), 7);
/// ```
- #[cfg(all(feature = "utils", not(feature = "cache")))]
- #[inline]
- pub fn shard_id(&self, shard_count: u64) -> u64 { ::utils::shard_id(self.0, shard_count) }
-
- /// 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<()> {
- http::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
- #[inline]
- pub fn start_prune(&self, days: u16) -> Result<GuildPrune> {
- let map = json!({
- "days": days,
- });
-
- http::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
+ #[cfg(feature = "utils")]
#[inline]
- pub fn unban<U: Into<UserId>>(&self, user_id: U) -> Result<()> {
- http::remove_ban(self.0, user_id.into().0)
+ pub fn shard_id(&self, shard_count: u64) -> u64 {
+ ::utils::shard_id(self.0, shard_count)
}
-
- /// Retrieve's the guild's vanity URL.
- ///
- /// **Note**: Requires the [Manage Guild] permission.
- ///
- /// [Manage Guild]: permissions/constant.MANAGE_GUILD.html
- #[inline]
- pub fn vanity_url(&self) -> Result<String> {
- http::get_guild_vanity_url(self.0)
- }
-
- /// 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>> { http::get_guild_webhooks(self.0) }
}
impl From<PartialGuild> for GuildId {
diff --git a/src/model/guild/member.rs b/src/model/guild/member.rs
index ce3dd01..262cf84 100644
--- a/src/model/guild/member.rs
+++ b/src/model/guild/member.rs
@@ -1,22 +1,8 @@
-use model::prelude::*;
use chrono::{DateTime, FixedOffset};
-use std::fmt::{
- Display,
- Formatter,
- Result as FmtResult
-};
-use super::deserialize_sync_user;
-
-#[cfg(all(feature = "builder", feature = "cache", feature = "model"))]
-use builder::EditMember;
-#[cfg(all(feature = "cache", feature = "model"))]
-use internal::prelude::*;
-#[cfg(feature = "model")]
+use model::prelude::*;
use std::borrow::Cow;
-#[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
-use utils::Colour;
-#[cfg(all(feature = "cache", feature = "model"))]
-use {CACHE, http, utils};
+use std::cell::RefCell;
+use super::deserialize_user;
/// A trait for allowing both u8 or &str or (u8, &str) to be passed into the `ban` methods in `Guild` and `Member`.
pub trait BanOptions {
@@ -70,138 +56,12 @@ pub struct Member {
/// Vector of Ids of [`Role`]s given to the member.
pub roles: Vec<RoleId>,
/// Attached User struct.
- #[serde(deserialize_with = "deserialize_sync_user",
- serialize_with = "serialize_sync_user")]
- pub user: Arc<RwLock<User>>,
+ #[serde(deserialize_with = "deserialize_user",
+ serialize_with = "serialize_user")]
+ pub user: Rc<RefCell<User>>,
}
-#[cfg(feature = "model")]
impl Member {
- /// Adds a [`Role`] to the member, editing its roles in-place if the request
- /// was successful.
- ///
- /// **Note**: Requires the [Manage Roles] permission.
- ///
- /// [`Role`]: struct.Role.html
- /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
- #[cfg(feature = "cache")]
- pub fn add_role<R: Into<RoleId>>(&mut self, role_id: R) -> Result<()> {
- let role_id = role_id.into();
-
- if self.roles.contains(&role_id) {
- return Ok(());
- }
-
- match http::add_member_role(self.guild_id.0, self.user.read().id.0, role_id.0) {
- Ok(()) => {
- self.roles.push(role_id);
-
- Ok(())
- },
- Err(why) => Err(why),
- }
- }
-
- /// Adds one or multiple [`Role`]s to the member, editing
- /// its roles in-place if the request was successful.
- ///
- /// **Note**: Requires the [Manage Roles] permission.
- ///
- /// [`Role`]: struct.Role.html
- /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
- #[cfg(feature = "cache")]
- pub fn add_roles(&mut self, role_ids: &[RoleId]) -> Result<()> {
- self.roles.extend_from_slice(role_ids);
-
- let mut builder = EditMember::default();
- builder.roles(&self.roles);
- let map = utils::vecmap_to_json_map(builder.0);
-
- match http::edit_member(self.guild_id.0, self.user.read().id.0, &map) {
- Ok(()) => Ok(()),
- Err(why) => {
- self.roles.retain(|r| !role_ids.contains(r));
-
- Err(why)
- },
- }
- }
-
- /// Ban the member from its guild, deleting the last X number of
- /// days' worth of messages.
- ///
- /// **Note**: Requires the [Ban Members] permission.
- ///
- /// # Errors
- ///
- /// Returns a [`ModelError::GuildNotFound`] if the guild could not be
- /// found.
- ///
- /// [`ModelError::GuildNotFound`]: enum.ModelError.html#variant.GuildNotFound
- ///
- /// [Ban Members]: permissions/constant.BAN_MEMBERS.html
- #[cfg(feature = "cache")]
- pub fn ban<BO: BanOptions>(&self, ban_options: &BO) -> Result<()> {
- let dmd = ban_options.dmd();
- if dmd > 7 {
- return Err(Error::Model(ModelError::DeleteMessageDaysAmount(dmd)));
- }
-
- let reason = ban_options.reason();
-
- if reason.len() > 512 {
- return Err(Error::ExceededLimit(reason.to_string(), 512));
- }
-
- http::ban_user(
- self.guild_id.0,
- self.user.read().id.0,
- dmd,
- &*reason,
- )
- }
-
- /// Determines the member's colour.
- #[cfg(all(feature = "cache", feature = "utils"))]
- pub fn colour(&self) -> Option<Colour> {
- let cache = CACHE.read();
- let guild = cache.guilds.get(&self.guild_id)?.read();
-
- let mut roles = self.roles
- .iter()
- .filter_map(|role_id| guild.roles.get(role_id))
- .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)
- }
-
- /// Returns the "default channel" of the guild for the member.
- /// (This returns the first channel that can be read by the member, if there isn't
- /// one returns `None`)
- #[cfg(feature = "cache")]
- pub fn default_channel(&self) -> Option<Arc<RwLock<GuildChannel>>> {
- let guild = match self.guild_id.find() {
- Some(guild) => guild,
- None => return None,
- };
-
- let reader = guild.read();
-
- for (cid, channel) in &reader.channels {
- if reader.permissions_in(*cid, self.user.read().id).read_messages() {
- return Some(Arc::clone(channel));
- }
- }
-
- None
- }
-
/// Calculates the member's display name.
///
/// The nickname takes priority over the member's username if it exists.
@@ -210,256 +70,23 @@ impl Member {
self.nick
.as_ref()
.map(Cow::Borrowed)
- .unwrap_or_else(|| Cow::Owned(self.user.read().name.clone()))
+ .unwrap_or_else(|| {
+ Cow::Owned(unsafe { (*self.user.as_ptr()).name.clone() })
+ })
}
/// Returns the DiscordTag of a Member, taking possible nickname into account.
#[inline]
pub fn distinct(&self) -> String {
- format!(
- "{}#{}",
- self.display_name(),
- self.user.read().discriminator
- )
- }
-
- /// Edits the member with the given data. See [`Guild::edit_member`] for
- /// more information.
- ///
- /// See [`EditMember`] for the permission(s) required for separate builder
- /// methods, as well as usage of this.
- ///
- /// [`Guild::edit_member`]: ../model/guild/struct.Guild.html#method.edit_member
- /// [`EditMember`]: ../builder/struct.EditMember.html
- #[cfg(feature = "cache")]
- pub fn edit<F: FnOnce(EditMember) -> EditMember>(&self, f: F) -> Result<()> {
- let map = utils::vecmap_to_json_map(f(EditMember::default()).0);
-
- http::edit_member(self.guild_id.0, self.user.read().id.0, &map)
- }
-
- /// Retrieves the ID and position of the member's highest role in the
- /// hierarchy, if they have one.
- ///
- /// This _may_ return `None` if:
- ///
- /// - the user has roles, but they are not present in the cache for cache
- /// inconsistency reasons
- /// - you already have a write lock to the member's guild
- ///
- /// The "highest role in hierarchy" is defined as the role with the highest
- /// position. If two or more roles have the same highest position, then the
- /// role with the lowest ID is the highest.
- #[cfg(feature = "cache")]
- pub fn highest_role_info(&self) -> Option<(RoleId, i64)> {
- let guild = self.guild_id.find()?;
- let reader = guild.try_read()?;
-
- let mut highest = None;
-
- for role_id in &self.roles {
- if let Some(role) = reader.roles.get(&role_id) {
- // Skip this role if this role in iteration has:
- //
- // - a position less than the recorded highest
- // - a position equal to the recorded, but a higher ID
- if let Some((id, pos)) = highest {
- if role.position < pos || (role.position == pos && role.id > id) {
- continue;
- }
- }
-
- highest = Some((role.id, role.position));
- }
+ unsafe {
+ let user = &*self.user.as_ptr();
+
+ format!(
+ "{}#{}",
+ self.display_name(),
+ user.discriminator,
+ )
}
-
- highest
- }
-
- /// Kick the member from the guild.
- ///
- /// **Note**: Requires the [Kick Members] permission.
- ///
- /// # Examples
- ///
- /// Kick a member from its guild:
- ///
- /// ```rust,ignore
- /// // assuming a `member` has already been bound
- /// match member.kick() {
- /// Ok(()) => println!("Successfully kicked member"),
- /// Err(Error::Model(ModelError::GuildNotFound)) => {
- /// println!("Couldn't determine guild of member");
- /// },
- /// Err(Error::Model(ModelError::InvalidPermissions(missing_perms))) => {
- /// println!("Didn't have permissions; missing: {:?}", missing_perms);
- /// },
- /// _ => {},
- /// }
- /// ```
- ///
- /// # Errors
- ///
- /// Returns a [`ModelError::GuildNotFound`] if the Id of the member's guild
- /// could not be determined.
- ///
- /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`]
- /// if the current user does not have permission to perform the kick.
- ///
- /// [`ModelError::GuildNotFound`]: enum.ModelError.html#variant.GuildNotFound
- /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
- /// [Kick Members]: permissions/constant.KICK_MEMBERS.html
- pub fn kick(&self) -> Result<()> {
- #[cfg(feature = "cache")]
- {
- let cache = CACHE.read();
-
- if let Some(guild) = cache.guilds.get(&self.guild_id) {
- let req = Permissions::KICK_MEMBERS;
- let reader = guild.read();
-
- if !reader.has_perms(req) {
- return Err(Error::Model(ModelError::InvalidPermissions(req)));
- }
-
- reader.check_hierarchy(self.user.read().id)?;
- }
- }
-
- self.guild_id.kick(self.user.read().id)
- }
-
- /// Returns the guild-level permissions for the member.
- ///
- /// # Examples
- ///
- /// ```rust,ignore
- /// // assuming there's a `member` variable gotten from anything.
- /// println!("The permission bits for the member are: {}",
- /// member.permissions().expect("permissions").bits);
- /// ```
- ///
- /// # Errors
- ///
- /// Returns a [`ModelError::GuildNotFound`] if the guild the member's in could not be
- /// found in the cache.
- ///
- /// And/or returns [`ModelError::ItemMissing`] if the "default channel" of the guild is not
- /// found.
- ///
- /// [`ModelError::GuildNotFound`]: enum.ModelError.html#variant.GuildNotFound
- /// [`ModelError::ItemMissing`]: enum.ModelError.html#variant.ItemMissing
- #[cfg(feature = "cache")]
- pub fn permissions(&self) -> Result<Permissions> {
- let guild = match self.guild_id.find() {
- Some(guild) => guild,
- None => return Err(From::from(ModelError::GuildNotFound)),
- };
-
- let reader = guild.read();
-
- Ok(reader.member_permissions(self.user.read().id))
- }
-
- /// Removes a [`Role`] from the member, editing its roles in-place if the
- /// request was successful.
- ///
- /// **Note**: Requires the [Manage Roles] permission.
- ///
- /// [`Role`]: struct.Role.html
- /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
- #[cfg(feature = "cache")]
- pub fn remove_role<R: Into<RoleId>>(&mut self, role_id: R) -> Result<()> {
- let role_id = role_id.into();
-
- if !self.roles.contains(&role_id) {
- return Ok(());
- }
-
- match http::remove_member_role(self.guild_id.0, self.user.read().id.0, role_id.0) {
- Ok(()) => {
- self.roles.retain(|r| r.0 != role_id.0);
-
- Ok(())
- },
- Err(why) => Err(why),
- }
- }
-
- /// Removes one or multiple [`Role`]s from the member.
- ///
- /// **Note**: Requires the [Manage Roles] permission.
- ///
- /// [`Role`]: struct.Role.html
- /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
- #[cfg(feature = "cache")]
- pub fn remove_roles(&mut self, role_ids: &[RoleId]) -> Result<()> {
- self.roles.retain(|r| !role_ids.contains(r));
-
- let mut builder = EditMember::default();
- builder.roles(&self.roles);
- let map = utils::vecmap_to_json_map(builder.0);
-
- match http::edit_member(self.guild_id.0, self.user.read().id.0, &map) {
- Ok(()) => Ok(()),
- Err(why) => {
- self.roles.extend_from_slice(role_ids);
-
- Err(why)
- },
- }
- }
-
- /// Retrieves the full role data for the user's roles.
- ///
- /// This is shorthand for manually searching through the CACHE.
- ///
- /// If role data can not be found for the member, then `None` is returned.
- #[cfg(feature = "cache")]
- pub fn roles(&self) -> Option<Vec<Role>> {
- self
- .guild_id
- .find()
- .map(|g| g
- .read()
- .roles
- .values()
- .filter(|role| self.roles.contains(&role.id))
- .cloned()
- .collect())
- }
-
- /// Unbans the [`User`] from the guild.
- ///
- /// **Note**: Requires the [Ban Members] permission.
- ///
- /// # Errors
- ///
- /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`]
- /// if the current user does not have permission to perform bans.
- ///
- /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
- /// [`User`]: struct.User.html
- /// [Ban Members]: permissions/constant.BAN_MEMBERS.html
- #[cfg(feature = "cache")]
- pub fn unban(&self) -> Result<()> {
- http::remove_ban(self.guild_id.0, self.user.read().id.0)
- }
-}
-
-impl Display for Member {
- /// Mentions the user so that they receive a notification.
- ///
- /// # Examples
- ///
- /// ```rust,ignore
- /// // assumes a `member` has already been bound
- /// println!("{} is a member!", member);
- /// ```
- ///
- // This is in the format of `<@USER_ID>`.
- fn fmt(&self, f: &mut Formatter) -> FmtResult {
- Display::fmt(&self.user.read().mention(), f)
}
}
diff --git a/src/model/guild/mod.rs b/src/model/guild/mod.rs
index 9e4d8ef..5abf40f 100644
--- a/src/model/guild/mod.rs
+++ b/src/model/guild/mod.rs
@@ -17,23 +17,15 @@ pub use self::role::*;
pub use self::audit_log::*;
use chrono::{DateTime, FixedOffset};
+use constants::LARGE_THRESHOLD;
use model::prelude::*;
use serde::de::Error as DeError;
use serde_json;
-use super::utils::*;
-
-#[cfg(all(feature = "cache", feature = "model"))]
-use CACHE;
-#[cfg(feature = "model")]
-use http;
-#[cfg(feature = "model")]
-use builder::{EditGuild, EditMember, EditRole};
-#[cfg(feature = "model")]
-use constants::LARGE_THRESHOLD;
-#[cfg(feature = "model")]
-use std;
-#[cfg(feature = "model")]
use std::borrow::Cow;
+use std::cell::RefCell;
+use std::rc::Rc;
+use std;
+use super::utils::*;
/// A representation of a banning of a user.
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Hash, Serialize)]
@@ -58,8 +50,8 @@ pub struct Guild {
///
/// This contains all channels regardless of permissions (i.e. the ability
/// of the bot to read from or connect to them).
- #[serde(serialize_with = "serialize_gen_locked_map")]
- pub channels: HashMap<ChannelId, Arc<RwLock<GuildChannel>>>,
+ #[serde(serialize_with = "serialize_gen_rc_map")]
+ pub channels: HashMap<ChannelId, Rc<RefCell<GuildChannel>>>,
/// Indicator of whether notifications for all messages are enabled by
/// default in the guild.
pub default_message_notifications: DefaultMessageNotificationLevel,
@@ -102,8 +94,8 @@ pub struct Guild {
/// the library.
///
/// [`ReadyEvent`]: events/struct.ReadyEvent.html
- #[serde(serialize_with = "serialize_gen_map")]
- pub members: HashMap<UserId, Member>,
+ #[serde(serialize_with = "serialize_gen_rc_map")]
+ pub members: HashMap<UserId, Rc<RefCell<Member>>>,
/// Indicator of whether the guild requires multi-factor authentication for
/// [`Role`]s or [`User`]s with moderation permissions.
///
@@ -119,13 +111,13 @@ pub struct Guild {
/// A mapping of [`User`]s' Ids to their current presences.
///
/// [`User`]: struct.User.html
- #[serde(serialize_with = "serialize_gen_map")]
- pub presences: HashMap<UserId, Presence>,
+ #[serde(serialize_with = "serialize_gen_rc_map")]
+ pub presences: HashMap<UserId, Rc<RefCell<Presence>>>,
/// The region that the voice servers that the guild uses are located in.
pub region: String,
/// A mapping of the guild's roles.
- #[serde(serialize_with = "serialize_gen_map")]
- pub roles: HashMap<RoleId, Role>,
+ #[serde(serialize_with = "serialize_gen_rc_map")]
+ pub roles: HashMap<RoleId, Rc<RefCell<Role>>>,
/// An identifying hash of the guild's splash icon.
///
/// If the [`InviteSplash`] feature is enabled, this can be used to generate
@@ -144,28 +136,14 @@ pub struct Guild {
pub voice_states: HashMap<UserId, VoiceState>,
}
-#[cfg(feature = "model")]
impl Guild {
- #[cfg(feature = "cache")]
- fn check_hierarchy(&self, other_user: UserId) -> Result<()> {
- let current_id = CACHE.read().user.id;
-
- if let Some(higher) = self.greater_member_hierarchy(other_user, current_id) {
- if higher != current_id {
- return Err(Error::Model(ModelError::Hierarchy));
- }
- }
-
- Ok(())
- }
-
/// Returns the "default" channel of the guild for the passed user id.
/// (This returns the first channel that can be read by the user, if there isn't one,
/// returns `None`)
- pub fn default_channel(&self, uid: UserId) -> Option<Arc<RwLock<GuildChannel>>> {
+ pub fn default_channel(&self, uid: UserId) -> Option<Rc<RefCell<GuildChannel>>> {
for (cid, channel) in &self.channels {
if self.permissions_in(*cid, uid).read_messages() {
- return Some(Arc::clone(channel));
+ return Some(Rc::clone(channel));
}
}
@@ -177,11 +155,11 @@ impl Guild {
/// returns `None`)
/// Note however that this is very costy if used in a server with lots of channels,
/// members, or both.
- pub fn default_channel_guaranteed(&self) -> Option<Arc<RwLock<GuildChannel>>> {
+ pub fn default_channel_guaranteed(&self) -> Option<Rc<RefCell<GuildChannel>>> {
for (cid, channel) in &self.channels {
for memid in self.members.keys() {
if self.permissions_in(*cid, *memid).read_messages() {
- return Some(Arc::clone(channel));
+ return Some(Rc::clone(channel));
}
}
}
@@ -189,537 +167,6 @@ impl Guild {
None
}
- #[cfg(feature = "cache")]
- fn has_perms(&self, mut permissions: Permissions) -> bool {
- let user_id = CACHE.read().user.id;
-
- let perms = self.member_permissions(user_id);
- permissions.remove(perms);
-
- permissions.is_empty()
- }
-
- /// Ban a [`User`] from the guild. All messages by the
- /// user within the last given number of days given will be deleted.
- ///
- /// Refer to the documentation for [`Guild::ban`] for more information.
- ///
- /// **Note**: Requires the [Ban Members] permission.
- ///
- /// # Examples
- ///
- /// Ban a member and remove all messages they've sent in the last 4 days:
- ///
- /// ```rust,ignore
- /// // assumes a `user` and `guild` have already been bound
- /// let _ = guild.ban(user, 4);
- /// ```
- ///
- /// # Errors
- ///
- /// Returns a [`ModelError::InvalidPermissions`] if the current user does
- /// not have permission to perform bans.
- ///
- /// Returns a [`ModelError::DeleteMessageDaysAmount`] if the number of
- /// days' worth of messages to delete is over the maximum.
- ///
- /// [`ModelError::DeleteMessageDaysAmount`]:
- /// enum.ModelError.html#variant.DeleteMessageDaysAmount
- /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
- /// [`Guild::ban`]: struct.Guild.html#method.ban
- /// [`User`]: struct.User.html
- /// [Ban Members]: permissions/constant.BAN_MEMBERS.html
- pub fn ban<U: Into<UserId>, BO: BanOptions>(&self, user: U, options: &BO) -> Result<()> {
- let user = user.into();
-
- #[cfg(feature = "cache")]
- {
- let req = Permissions::BAN_MEMBERS;
-
- if !self.has_perms(req) {
- return Err(Error::Model(ModelError::InvalidPermissions(req)));
- }
-
- self.check_hierarchy(user)?;
- }
-
- self.id.ban(user, options)
- }
-
- /// Retrieves a list of [`Ban`]s for the guild.
- ///
- /// **Note**: Requires the [Ban Members] permission.
- ///
- /// # Errors
- ///
- /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`]
- /// if the current user does not have permission to perform bans.
- ///
- /// [`Ban`]: struct.Ban.html
- /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
- /// [Ban Members]: permissions/constant.BAN_MEMBERS.html
- pub fn bans(&self) -> Result<Vec<Ban>> {
- #[cfg(feature = "cache")]
- {
- let req = Permissions::BAN_MEMBERS;
-
- if !self.has_perms(req) {
- return Err(Error::Model(ModelError::InvalidPermissions(req)));
- }
- }
-
- self.id.bans()
- }
-
- /// Retrieves a list of [`AuditLogs`] for the guild.
- ///
- /// [`AuditLogs`]: audit_log/struct.AuditLogs.html
- #[inline]
- pub fn audit_logs(&self, action_type: Option<u8>,
- user_id: Option<UserId>,
- before: Option<AuditLogEntryId>,
- limit: Option<u8>) -> Result<AuditLogs> {
- self.id.audit_logs(action_type, user_id, before, limit)
- }
-
- /// Gets all of the guild's channels over the REST API.
- ///
- /// [`Guild`]: struct.Guild.html
- #[inline]
- pub fn channels(&self) -> Result<HashMap<ChannelId, GuildChannel>> { self.id.channels() }
-
- /// 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 = json!({
- "icon": icon,
- "name": name,
- "region": region.name(),
- });
-
- http::create_guild(&map)
- }
-
- /// Creates a new [`Channel`] in the guild.
- ///
- /// **Note**: Requires the [Manage Channels] permission.
- ///
- /// # Examples
- ///
- /// ```rust,ignore
- /// use serenity::model::ChannelType;
- ///
- /// // assuming a `guild` has already been bound
- ///
- /// let _ = guild.create_channel("my-test-channel", ChannelType::Text, None);
- /// ```
- ///
- /// # Errors
- ///
- /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`]
- /// if the current user does not have permission to perform bans.
- ///
- /// [`Channel`]: struct.Channel.html
- /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
- /// [Manage Channels]: permissions/constant.MANAGE_CHANNELS.html
- pub fn create_channel<C>(&self, name: &str, kind: ChannelType, category: C) -> Result<GuildChannel>
- where C: Into<Option<ChannelId>> {
- #[cfg(feature = "cache")]
- {
- let req = Permissions::MANAGE_CHANNELS;
-
- if !self.has_perms(req) {
- return Err(Error::Model(ModelError::InvalidPermissions(req)));
- }
- }
-
- self.id.create_channel(name, kind, category)
- }
-
- /// Creates an emoji in the guild with a name and base64-encoded image. The
- /// [`utils::read_image`] function is provided for you as a simple method to
- /// read an image and encode it into base64, if you are reading from the
- /// filesystem.
- ///
- /// The name of the emoji must be at least 2 characters long and can only
- /// contain alphanumeric characters and underscores.
- ///
- /// Requires the [Manage Emojis] permission.
- ///
- /// # Examples
- ///
- /// See the [`EditProfile::avatar`] example for an in-depth example as to
- /// how to read an image from the filesystem and encode it as base64. Most
- /// of the example can be applied similarly for this method.
- ///
- /// [`EditProfile::avatar`]: ../builder/struct.EditProfile.html#method.avatar
- /// [`utils::read_image`]: ../fn.read_image.html
- /// [Manage Emojis]: permissions/constant.MANAGE_EMOJIS.html
- #[inline]
- pub fn create_emoji(&self, name: &str, image: &str) -> 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.
- ///
- /// **Note**: Requires the [Manage Roles] permission.
- ///
- /// # Examples
- ///
- /// Create a role which can be mentioned, with the name 'test':
- ///
- /// ```rust,ignore
- /// // assuming a `guild` has been bound
- ///
- /// let role = guild.create_role(|r| r.hoist(true).name("role"));
- /// ```
- ///
- /// # Errors
- ///
- /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`]
- /// if the current user does not have permission to perform bans.
- ///
- /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
- /// [`Role`]: struct.Role.html
- /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
- pub fn create_role<F>(&self, f: F) -> Result<Role>
- where F: FnOnce(EditRole) -> EditRole {
- #[cfg(feature = "cache")]
- {
- let req = Permissions::MANAGE_ROLES;
-
- if !self.has_perms(req) {
- return Err(Error::Model(ModelError::InvalidPermissions(req)));
- }
- }
-
- 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.
- ///
- /// # Errors
- ///
- /// If the `cache` is enabled, then returns a [`ModelError::InvalidUser`]
- /// if the current user is not the guild owner.
- ///
- /// [`ModelError::InvalidUser`]: enum.ModelError.html#variant.InvalidUser
- pub fn delete(&self) -> Result<PartialGuild> {
- #[cfg(feature = "cache")]
- {
- if self.owner_id != CACHE.read().user.id {
- let req = Permissions::MANAGE_GUILD;
-
- return Err(Error::Model(ModelError::InvalidPermissions(req)));
- }
- }
-
- 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 `EditGuild`'s documentation for a full list of methods.
- ///
- /// **Note**: Requires the current user to have the [Manage Guild]
- /// permission.
- ///
- /// # Examples
- ///
- /// Change a guild's icon using a file name "icon.png":
- ///
- /// ```rust,ignore
- /// use serenity::utils;
- ///
- /// // We are using read_image helper function from utils.
- /// let base64_icon = utils::read_image("./icon.png")
- /// .expect("Failed to read image");
- ///
- /// guild.edit(|g| g.icon(base64_icon));
- /// ```
- ///
- /// # Errors
- ///
- /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`]
- /// if the current user does not have permission to perform bans.
- ///
- /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
- /// [Manage Guild]: permissions/constant.MANAGE_GUILD.html
- pub fn edit<F>(&mut self, f: F) -> Result<()>
- where F: FnOnce(EditGuild) -> EditGuild {
- #[cfg(feature = "cache")]
- {
- let req = Permissions::MANAGE_GUILD;
-
- if !self.has_perms(req) {
- return Err(Error::Model(ModelError::InvalidPermissions(req)));
- }
- }
-
- 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
- /// 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.
- ///
- /// **Note**: Requires the [Change Nickname] permission.
- ///
- /// # Errors
- ///
- /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`]
- /// if the current user does not have permission to change their own
- /// nickname.
- ///
- /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
- /// [Change Nickname]: permissions/constant.CHANGE_NICKNAME.html
- pub fn edit_nickname(&self, new_nickname: Option<&str>) -> Result<()> {
- #[cfg(feature = "cache")]
- {
- let req = Permissions::CHANGE_NICKNAME;
-
- if !self.has_perms(req) {
- return Err(Error::Model(ModelError::InvalidPermissions(req)));
- }
- }
-
- 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)
- }
-
- /// Edits the order of [`Role`]s
- /// Requires the [Manage Roles] permission.
- ///
- /// # Examples
- ///
- /// Change the order of a role:
- ///
- /// ```rust,ignore
- /// use serenity::model::RoleId;
- /// guild.edit_role_position(RoleId(8), 2);
- /// ```
- ///
- /// [`Role`]: struct.Role.html
- /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
- #[inline]
- pub fn edit_role_position<R>(&self, role_id: R, position: u64) -> Result<Vec<Role>>
- where R: Into<RoleId> {
- self.id.edit_role_position(role_id, position)
- }
-
- /// 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() }
-
- /// Returns which of two [`User`]s has a higher [`Member`] hierarchy.
- ///
- /// Hierarchy is essentially who has the [`Role`] with the highest
- /// [`position`].
- ///
- /// Returns [`None`] if at least one of the given users' member instances
- /// is not present. Returns `None` if the users have the same hierarchy, as
- /// neither are greater than the other.
- ///
- /// If both user IDs are the same, `None` is returned. If one of the users
- /// is the guild owner, their ID is returned.
- #[cfg(feature = "cache")]
- pub fn greater_member_hierarchy<T, U>(&self, lhs_id: T, rhs_id: U)
- -> Option<UserId> where T: Into<UserId>, U: Into<UserId> {
- let lhs_id = lhs_id.into();
- let rhs_id = rhs_id.into();
-
- // Check that the IDs are the same. If they are, neither is greater.
- if lhs_id == rhs_id {
- return None;
- }
-
- // Check if either user is the guild owner.
- if lhs_id == self.owner_id {
- return Some(lhs_id);
- } else if rhs_id == self.owner_id {
- return Some(rhs_id);
- }
-
- let lhs = self.members.get(&lhs_id)?
- .highest_role_info()
- .unwrap_or((RoleId(0), 0));
- let rhs = self.members.get(&rhs_id)?
- .highest_role_info()
- .unwrap_or((RoleId(0), 0));
-
- // If LHS and RHS both have no top position or have the same role ID,
- // then no one wins.
- if (lhs.1 == 0 && rhs.1 == 0) || (lhs.0 == rhs.0) {
- return None;
- }
-
- // If LHS's top position is higher than RHS, then LHS wins.
- if lhs.1 > rhs.1 {
- return Some(lhs_id)
- }
-
- // If RHS's top position is higher than LHS, then RHS wins.
- if rhs.1 > lhs.1 {
- return Some(rhs_id);
- }
-
- // If LHS and RHS both have the same position, but LHS has the lower
- // role ID, then LHS wins.
- //
- // If RHS has the higher role ID, then RHS wins.
- if lhs.1 == rhs.1 && lhs.0 < rhs.0 {
- Some(lhs_id)
- } else {
- Some(rhs_id)
- }
- }
-
/// Returns the formatted URL of the guild's icon, if one exists.
pub fn icon_url(&self) -> Option<String> {
self.icon
@@ -727,81 +174,21 @@ impl Guild {
.map(|icon| format!(cdn!("/icons/{}/{}.webp"), self.id, icon))
}
- /// Gets all integration of the guild.
- ///
- /// This performs a request over the REST API.
- #[inline]
- pub fn integrations(&self) -> Result<Vec<Integration>> { self.id.integrations() }
-
- /// Retrieves the active invites for the guild.
- ///
- /// **Note**: Requires the [Manage Guild] permission.
- ///
- /// # Errors
- ///
- /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`]
- /// if the current user does not have permission to perform bans.
- ///
- /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
- /// [Manage Guild]: permissions/constant.MANAGE_GUILD.html
- pub fn invites(&self) -> Result<Vec<RichInvite>> {
- #[cfg(feature = "cache")]
- {
- let req = Permissions::MANAGE_GUILD;
-
- if !self.has_perms(req) {
- return Err(Error::Model(ModelError::InvalidPermissions(req)));
- }
- }
-
- self.id.invites()
- }
-
/// 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() > LARGE_THRESHOLD as usize }
-
- /// Kicks a [`Member`] from the guild.
- ///
- /// Requires the [Kick Members] permission.
- ///
- /// [`Member`]: struct.Member.html
- /// [Kick Members]: permissions/constant.KICK_MEMBERS.html
- #[inline]
- pub fn kick<U: Into<UserId>>(&self, user_id: U) -> Result<()> { self.id.kick(user_id) }
-
- /// Leaves the guild.
- #[inline]
- pub fn leave(&self) -> Result<()> { self.id.leave() }
-
- /// Gets a user's [`Member`] for the guild by Id.
- ///
- /// [`Guild`]: struct.Guild.html
- /// [`Member`]: struct.Member.html
- #[inline]
- pub fn member<U: Into<UserId>>(&self, user_id: U) -> Result<Member> { self.id.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 members<U>(&self, limit: Option<u64>, after: Option<U>) -> Result<Vec<Member>>
- where U: Into<UserId> {
- self.id.members(limit, after)
+ pub fn is_large(&self) -> bool {
+ self.members.len() > LARGE_THRESHOLD as usize
}
/// Gets a list of all the members (satisfying the status provided to the function) in this
/// guild.
- pub fn members_with_status(&self, status: OnlineStatus) -> Vec<&Member> {
+ pub fn members_with_status(&self, status: OnlineStatus)
+ -> Vec<&Rc<RefCell<Member>>> {
let mut members = vec![];
for (&id, member) in &self.members {
- match self.presences.get(&id) {
+ match self.presences.get(&id).and_then(|x| x.try_borrow().ok()) {
Some(presence) => if status == presence.status {
members.push(member);
},
@@ -828,7 +215,7 @@ impl Guild {
/// - **username and discriminator**: "zey#5479"
///
/// [`Member`]: struct.Member.html
- pub fn member_named(&self, name: &str) -> Option<&Member> {
+ pub fn member_named(&self, name: &str) -> Option<&Rc<RefCell<Member>>> {
let (name, discrim) = if let Some(pos) = name.rfind('#') {
let split = name.split_at(pos + 1);
@@ -851,9 +238,18 @@ impl Guild {
self.members
.values()
.find(|member| {
- let name_matches = member.user.read().name == name;
+ let member = match member.try_borrow().ok() {
+ Some(member) => member,
+ None => return false,
+ };
+ let user = match member.user.try_borrow().ok() {
+ Some(user) => user,
+ None => return false,
+ };
+
+ let name_matches = user.name == name;
let discrim_matches = match discrim {
- Some(discrim) => member.user.read().discriminator == discrim,
+ Some(discrim) => user.discriminator == discrim,
None => true,
};
@@ -862,7 +258,7 @@ impl Guild {
.or_else(|| {
self.members
.values()
- .find(|member| member.nick.as_ref().map_or(false, |nick| nick == name))
+ .find(|member| member.borrow().nick.as_ref().map_or(false, |nick| nick == name))
})
}
@@ -876,18 +272,23 @@ impl Guild {
/// - "zeya", "zeyaa", "zeyla", "zeyzey", "zeyzeyzey"
///
/// [`Member`]: struct.Member.html
- pub fn members_starting_with(&self, prefix: &str, case_sensitive: bool, sorted: bool) -> Vec<&Member> {
- let mut members: Vec<&Member> = self.members
+ pub fn members_starting_with(&self, prefix: &str, case_sensitive: bool, sorted: bool) -> Vec<&Rc<RefCell<Member>>> {
+ let mut members: Vec<&Rc<RefCell<Member>>> = self.members
.values()
.filter(|member|
-
if case_sensitive {
- member.user.read().name.starts_with(prefix)
+ let member = member.borrow();
+ let user = member.user.borrow();
+
+ user.name.starts_with(prefix)
} else {
- starts_with_case_insensitive(&member.user.read().name, prefix)
+ let member = member.borrow();
+ let user = member.user.borrow();
+
+ starts_with_case_insensitive(&user.name, prefix)
}
- || member.nick.as_ref()
+ || member.borrow().nick.as_ref()
.map_or(false, |nick|
if case_sensitive {
@@ -899,26 +300,28 @@ impl Guild {
if sorted {
members
.sort_by(|a, b| {
+ let (a, b) = (a.borrow(), b.borrow());
+
let name_a = match a.nick {
Some(ref nick) => {
- if contains_case_insensitive(&a.user.read().name[..], prefix) {
- Cow::Owned(a.user.read().name.clone())
+ if contains_case_insensitive(&a.user.borrow().name[..], prefix) {
+ Cow::Owned(a.user.borrow().name.clone())
} else {
Cow::Borrowed(nick)
}
},
- None => Cow::Owned(a.user.read().name.clone()),
+ None => Cow::Owned(a.user.borrow().name.clone()),
};
let name_b = match b.nick {
Some(ref nick) => {
- if contains_case_insensitive(&b.user.read().name[..], prefix) {
- Cow::Owned(b.user.read().name.clone())
+ if contains_case_insensitive(&b.user.borrow().name[..], prefix) {
+ Cow::Owned(b.user.borrow().name.clone())
} else {
Cow::Borrowed(nick)
}
},
- None => Cow::Owned(b.user.read().name.clone()),
+ None => Cow::Owned(b.user.borrow().name.clone()),
};
closest_to_origin(prefix, &name_a[..], &name_b[..])
@@ -951,18 +354,24 @@ impl Guild {
/// as both fields have to be considered again for sorting.
///
/// [`Member`]: struct.Member.html
- pub fn members_containing(&self, substring: &str, case_sensitive: bool, sorted: bool) -> Vec<&Member> {
- let mut members: Vec<&Member> = self.members
+ pub fn members_containing(&self, substring: &str, case_sensitive: bool, sorted: bool) -> Vec<&Rc<RefCell<Member>>> {
+ let mut members: Vec<&Rc<RefCell<Member>>> = self.members
.values()
.filter(|member|
if case_sensitive {
- member.user.read().name.contains(substring)
+ let member = member.borrow();
+ let user = member.user.borrow();
+
+ user.name.contains(substring)
} else {
- contains_case_insensitive(&member.user.read().name, substring)
+ let member = member.borrow();
+ let user = member.user.borrow();
+
+ contains_case_insensitive(&user.name, substring)
}
- || member.nick.as_ref()
+ || member.borrow().nick.as_ref()
.map_or(false, |nick| {
if case_sensitive {
@@ -975,26 +384,28 @@ impl Guild {
if sorted {
members
.sort_by(|a, b| {
+ let (a, b) = (a.borrow(), b.borrow());
+
let name_a = match a.nick {
Some(ref nick) => {
- if contains_case_insensitive(&a.user.read().name[..], substring) {
- Cow::Owned(a.user.read().name.clone())
+ if contains_case_insensitive(&a.user.borrow().name[..], substring) {
+ Cow::Owned(a.user.borrow().name.clone())
} else {
Cow::Borrowed(nick)
}
},
- None => Cow::Owned(a.user.read().name.clone()),
+ None => Cow::Owned(a.user.borrow().name.clone()),
};
let name_b = match b.nick {
Some(ref nick) => {
- if contains_case_insensitive(&b.user.read().name[..], substring) {
- Cow::Owned(b.user.read().name.clone())
+ if contains_case_insensitive(&b.user.borrow().name[..], substring) {
+ Cow::Owned(b.user.borrow().name.clone())
} else {
Cow::Borrowed(nick)
}
},
- None => Cow::Owned(b.user.read().name.clone()),
+ None => Cow::Owned(b.user.borrow().name.clone()),
};
closest_to_origin(substring, &name_a[..], &name_b[..])
@@ -1021,22 +432,34 @@ impl Guild {
/// - "zey", "azey", "zeyla", "zeylaa", "zeyzeyzey"
///
/// [`Member`]: struct.Member.html
- pub fn members_username_containing(&self, substring: &str, case_sensitive: bool, sorted: bool) -> Vec<&Member> {
- let mut members: Vec<&Member> = self.members
+ pub fn members_username_containing(&self, substring: &str, case_sensitive: bool, sorted: bool) -> Vec<&Rc<RefCell<Member>>> {
+ let mut members: Vec<&Rc<RefCell<Member>>> = self.members
.values()
.filter(|member| {
+ let member = match member.try_borrow().ok() {
+ Some(member) => member,
+ None => return false,
+ };
+ let user = match member.user.try_borrow().ok() {
+ Some(user) => user,
+ None => return false,
+ };
+
if case_sensitive {
- member.user.read().name.contains(substring)
+ user.name.contains(substring)
} else {
- contains_case_insensitive(&member.user.read().name, substring)
+ contains_case_insensitive(&user.name, substring)
}
}).collect();
if sorted {
members
.sort_by(|a, b| {
- let name_a = &a.user.read().name;
- let name_b = &b.user.read().name;
+ let (a, b) = (a.borrow(), b.borrow());
+ let (a_user, b_user) = (a.user.borrow(), b.user.borrow());
+
+ let name_a = &a_user.name;
+ let name_b = &b_user.name;
closest_to_origin(substring, &name_a[..], &name_b[..])
});
members
@@ -1064,35 +487,42 @@ impl Guild {
/// a nick, the username will be used (this should never happen).
///
/// [`Member`]: struct.Member.html
- pub fn members_nick_containing(&self, substring: &str, case_sensitive: bool, sorted: bool) -> Vec<&Member> {
- let mut members: Vec<&Member> = self.members
+ pub fn members_nick_containing(&self, substring: &str, case_sensitive: bool, sorted: bool) -> Vec<&Rc<RefCell<Member>>> {
+ let mut members = self.members
.values()
- .filter(|member|
+ .filter(|member| {
+ let member = match member.try_borrow() {
+ Ok(member) => member,
+ Err(_) => return false,
+ };
+
member.nick.as_ref()
.map_or(false, |nick| {
-
if case_sensitive {
nick.contains(substring)
} else {
contains_case_insensitive(nick, substring)
}
- })).collect();
+ })
+ }).collect::<Vec<&Rc<RefCell<Member>>>>();
if sorted {
members
.sort_by(|a, b| {
+ let (a, b) = (a.borrow(), b.borrow());
+
let name_a = match a.nick {
Some(ref nick) => {
Cow::Borrowed(nick)
},
- None => Cow::Owned(a.user.read().name.clone()),
+ None => Cow::Owned(a.user.borrow().name.clone()),
};
let name_b = match b.nick {
Some(ref nick) => {
Cow::Borrowed(nick)
},
- None => Cow::Owned(b.user.read().name.clone()),
+ None => Cow::Owned(b.user.borrow().name.clone()),
};
closest_to_origin(substring, &name_a[..], &name_b[..])
@@ -1114,7 +544,7 @@ impl Guild {
return Permissions::all();
}
- let everyone = match self.roles.get(&RoleId(self.id.0)) {
+ let everyone = match self.roles.get(&RoleId(self.id.0)).and_then(|x| x.try_borrow().ok()) {
Some(everyone) => everyone,
None => {
error!(
@@ -1127,7 +557,7 @@ impl Guild {
},
};
- let member = match self.members.get(&user_id) {
+ let member = match self.members.get(&user_id).and_then(|x| x.try_borrow().ok()) {
Some(member) => member,
None => return everyone.permissions,
};
@@ -1135,7 +565,7 @@ impl Guild {
let mut permissions = everyone.permissions;
for role in &member.roles {
- if let Some(role) = self.roles.get(role) {
+ if let Some(role) = self.roles.get(role).and_then(|x| x.try_borrow().ok()) {
if role.permissions.contains(Permissions::ADMINISTRATOR) {
return Permissions::all();
}
@@ -1144,7 +574,7 @@ impl Guild {
} else {
warn!(
"(╯°□°)╯︵ ┻━┻ {} on {} has non-existent role {:?}",
- member.user.read().id,
+ member.user.borrow().id,
self.id,
role,
);
@@ -1154,17 +584,6 @@ impl Guild {
permissions
}
- /// Moves a member to a specific voice channel.
- ///
- /// Requires the [Move Members] permission.
- ///
- /// [Move Members]: permissions/constant.MOVE_MEMBERS.html
- #[inline]
- pub fn move_member<C, U>(&self, user_id: U, channel_id: C) -> Result<()>
- where C: Into<ChannelId>, U: Into<UserId> {
- self.id.move_member(user_id, channel_id)
- }
-
/// Alias for [`permissions_in`].
///
/// [`permissions_in`]: #method.permissions_in
@@ -1191,7 +610,7 @@ impl Guild {
let channel_id = channel_id.into();
// Start by retrieving the @everyone role's permissions.
- let everyone = match self.roles.get(&RoleId(self.id.0)) {
+ let everyone = match self.roles.get(&RoleId(self.id.0)).and_then(|x| x.try_borrow().ok()) {
Some(everyone) => everyone,
None => {
error!(
@@ -1207,18 +626,18 @@ impl Guild {
// Create a base set of permissions, starting with `@everyone`s.
let mut permissions = everyone.permissions;
- let member = match self.members.get(&user_id) {
+ let member = match self.members.get(&user_id).and_then(|x| x.try_borrow().ok()) {
Some(member) => member,
None => return everyone.permissions,
};
for &role in &member.roles {
- if let Some(role) = self.roles.get(&role) {
+ if let Some(role) = self.roles.get(&role).and_then(|x| x.try_borrow().ok()) {
permissions |= role.permissions;
} else {
warn!(
"(╯°□°)╯︵ ┻━┻ {} on {} has non-existent role {:?}",
- member.user.read().id,
+ member.user.borrow().id,
self.id,
role
);
@@ -1231,7 +650,7 @@ impl Guild {
}
if let Some(channel) = self.channels.get(&channel_id) {
- let channel = channel.read();
+ let channel = channel.borrow();
// If this is a text channel, then throw out voice permissions.
if channel.kind == ChannelType::Text {
@@ -1259,7 +678,7 @@ impl Guild {
continue;
}
- if let Some(role) = self.roles.get(&role) {
+ if let Some(role) = self.roles.get(&role).and_then(|x| x.try_borrow().ok()) {
data.push((role.position, overwrite.deny, overwrite.allow));
}
}
@@ -1316,59 +735,6 @@ impl Guild {
permissions
}
- /// Retrieves the count of the number of [`Member`]s that would be pruned
- /// with the number of given days.
- ///
- /// See the documentation on [`GuildPrune`] for more information.
- ///
- /// **Note**: Requires the [Kick Members] permission.
- ///
- /// # Errors
- ///
- /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`]
- /// if the current user does not have permission to perform bans.
- ///
- /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
- /// [`GuildPrune`]: struct.GuildPrune.html
- /// [`Member`]: struct.Member.html
- /// [Kick Members]: permissions/constant.KICK_MEMBERS.html
- pub fn prune_count(&self, days: u16) -> Result<GuildPrune> {
- #[cfg(feature = "cache")]
- {
- let req = Permissions::KICK_MEMBERS;
-
- if !self.has_perms(req) {
- return Err(Error::Model(ModelError::InvalidPermissions(req)));
- }
- }
-
- self.id.prune_count(days)
- }
-
- /// Re-orders the channels of the guild.
- ///
- /// Although not required, you should specify all channels' positions,
- /// regardless of whether they were updated. Otherwise, positioning can
- /// sometimes get weird.
- pub fn reorder_channels<It>(&self, channels: It) -> Result<()>
- where It: IntoIterator<Item = (ChannelId, u64)> {
- self.id.reorder_channels(channels)
- }
-
- /// Returns the Id of the shard associated with the guild.
- ///
- /// When the cache is enabled this will automatically retrieve the total
- /// number of shards.
- ///
- /// **Note**: When the cache is enabled, this function unlocks the cache to
- /// retrieve the total number of shards in use. If you already have the
- /// total, consider using [`utils::shard_id`].
- ///
- /// [`utils::shard_id`]: ../utils/fn.shard_id.html
- #[cfg(all(feature = "cache", feature = "utils"))]
- #[inline]
- pub fn shard_id(&self) -> u64 { self.id.shard_id() }
-
/// Returns the Id of the shard associated with the guild.
///
/// When the cache is enabled this will automatically retrieve the total
@@ -1389,7 +755,7 @@ impl Guild {
///
/// assert_eq!(guild.shard_id(17), 7);
/// ```
- #[cfg(all(feature = "utils", not(feature = "cache")))]
+ #[cfg(feature = "utils")]
#[inline]
pub fn shard_id(&self, shard_count: u64) -> u64 { self.id.shard_id(shard_count) }
@@ -1400,87 +766,6 @@ impl Guild {
.map(|icon| format!(cdn!("/splashes/{}/{}.webp"), self.id, icon))
}
- /// Starts an integration sync for the given integration Id.
- ///
- /// Requires the [Manage Guild] permission.
- ///
- /// [Manage Guild]: permissions/constant.MANAGE_GUILD.html
- #[inline]
- pub fn start_integration_sync<I: 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.
- ///
- /// **Note**: Requires the [Kick Members] permission.
- ///
- /// # Errors
- ///
- /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`]
- /// if the current user does not have permission to perform bans.
- ///
- /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
- /// [`GuildPrune`]: struct.GuildPrune.html
- /// [`Member`]: struct.Member.html
- /// [Kick Members]: permissions/constant.KICK_MEMBERS.html
- pub fn start_prune(&self, days: u16) -> Result<GuildPrune> {
- #[cfg(feature = "cache")]
- {
- let req = Permissions::KICK_MEMBERS;
-
- if !self.has_perms(req) {
- return Err(Error::Model(ModelError::InvalidPermissions(req)));
- }
- }
-
- self.id.start_prune(days)
- }
-
- /// Unbans the given [`User`] from the guild.
- ///
- /// **Note**: Requires the [Ban Members] permission.
- ///
- /// # Errors
- ///
- /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`]
- /// if the current user does not have permission to perform bans.
- ///
- /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
- /// [`User`]: struct.User.html
- /// [Ban Members]: permissions/constant.BAN_MEMBERS.html
- pub fn unban<U: Into<UserId>>(&self, user_id: U) -> Result<()> {
- #[cfg(feature = "cache")]
- {
- let req = Permissions::BAN_MEMBERS;
-
- if !self.has_perms(req) {
- return Err(Error::Model(ModelError::InvalidPermissions(req)));
- }
- }
-
- self.id.unban(user_id)
- }
-
- /// Retrieve's the guild's vanity URL.
- ///
- /// **Note**: Requires the [Manage Guild] permission.
- ///
- /// [Manage Guild]: permissions/constant.MANAGE_GUILD.html
- #[inline]
- pub fn vanity_url(&self) -> Result<String> {
- self.id.vanity_url()
- }
-
- /// 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() }
-
/// Obtain a reference to a role by its name.
///
/// **Note**: If two or more roles have the same name, obtained reference will be one of
@@ -1512,8 +797,15 @@ impl Guild {
///
/// client.start().unwrap();
/// ```
- pub fn role_by_name(&self, role_name: &str) -> Option<&Role> {
- self.roles.values().find(|role| role_name == role.name)
+ pub fn role_by_name(&self, role_name: &str) -> Option<&Rc<RefCell<Role>>> {
+ self.roles.values().find(|role| {
+ let role = match role.try_borrow().ok() {
+ Some(role) => role,
+ None => return false,
+ };
+
+ role_name == role.name
+ })
}
}
@@ -1678,13 +970,11 @@ impl<'de> Deserialize<'de> for Guild {
}
/// Checks if a `&str` contains another `&str`.
-#[cfg(feature = "model")]
fn contains_case_insensitive(to_look_at: &str, to_find: &str) -> bool {
to_look_at.to_lowercase().contains(to_find)
}
/// Checks if a `&str` starts with another `&str`.
-#[cfg(feature = "model")]
fn starts_with_case_insensitive(to_look_at: &str, to_find: &str) -> bool {
to_look_at.to_lowercase().starts_with(to_find)
}
@@ -1696,7 +986,6 @@ fn starts_with_case_insensitive(to_look_at: &str, to_find: &str) -> bool {
/// expected to contain `origin` as substring.
/// If not, using `closest_to_origin` would sort these
/// the end.
-#[cfg(feature = "model")]
fn closest_to_origin(origin: &str, word_a: &str, word_b: &str) -> std::cmp::Ordering {
let value_a = match word_a.find(origin) {
Some(value) => value + word_a.len(),
@@ -1782,7 +1071,6 @@ impl From<u64> for GuildContainer {
fn from(id: u64) -> GuildContainer { GuildContainer::Id(GuildId(id)) }
}
-#[cfg(feature = "model")]
impl InviteGuild {
/// Returns the formatted URL of the guild's splash image, if one exists.
pub fn splash_url(&self) -> Option<String> {
@@ -1814,7 +1102,6 @@ pub enum GuildStatus {
Offline(GuildUnavailable),
}
-#[cfg(feature = "model")]
impl GuildStatus {
/// Retrieves the Id of the inner [`Guild`].
///
diff --git a/src/model/guild/partial_guild.rs b/src/model/guild/partial_guild.rs
index d324517..39f158a 100644
--- a/src/model/guild/partial_guild.rs
+++ b/src/model/guild/partial_guild.rs
@@ -1,8 +1,8 @@
use model::prelude::*;
+use std::cell::RefCell;
+use std::rc::Rc;
use super::super::utils::{deserialize_emojis, deserialize_roles};
-#[cfg(feature = "model")]
-use builder::{EditGuild, EditMember, EditRole};
/// Partial information about a [`Guild`]. This does not include information
/// like member data.
@@ -28,281 +28,14 @@ pub struct PartialGuild {
pub name: String,
pub owner_id: UserId,
pub region: String,
- #[serde(deserialize_with = "deserialize_roles")] pub roles: HashMap<RoleId, Role>,
+ #[serde(deserialize_with = "deserialize_roles",
+ serialize_with = "serialize_gen_rc_map")]
+ pub roles: HashMap<RoleId, Rc<RefCell<Role>>>,
pub splash: Option<String>,
pub verification_level: VerificationLevel,
}
-#[cfg(feature = "model")]
impl PartialGuild {
- /// Ban a [`User`] from the guild. All messages by the
- /// user within the last given number of days given will be deleted. This
- /// may be a range between `0` and `7`.
- ///
- /// **Note**: Requires the [Ban Members] permission.
- ///
- /// # Examples
- ///
- /// Ban a member and remove all messages they've sent in the last 4 days:
- ///
- /// ```rust,ignore
- /// // assumes a `user` and `guild` have already been bound
- /// let _ = guild.ban(user, 4);
- /// ```
- ///
- /// # Errors
- ///
- /// Returns a [`ModelError::DeleteMessageDaysAmount`] if the number of
- /// days' worth of messages to delete is over the maximum.
- ///
- /// [`ModelError::DeleteMessageDaysAmount`]:
- /// enum.ModelError.html#variant.DeleteMessageDaysAmount
- /// [`User`]: struct.User.html
- /// [Ban Members]: permissions/constant.BAN_MEMBERS.html
- pub fn ban<U: Into<UserId>>(&self, user: U, delete_message_days: u8) -> Result<()> {
- if delete_message_days > 7 {
- return Err(Error::Model(
- ModelError::DeleteMessageDaysAmount(delete_message_days),
- ));
- }
-
- self.id.ban(user, &delete_message_days)
- }
-
- /// Gets a list of the guild's bans.
- ///
- /// Requires the [Ban Members] permission.
- ///
- /// [Ban Members]: permissions/constant.BAN_MEMBERS.html
- #[inline]
- pub fn bans(&self) -> Result<Vec<Ban>> { self.id.bans() }
-
- /// Gets all of the guild's channels over the REST API.
- ///
- /// [`Guild`]: struct.Guild.html
- #[inline]
- pub fn channels(&self) -> Result<HashMap<ChannelId, GuildChannel>> { self.id.channels() }
-
- /// Creates a [`GuildChannel`] in the guild.
- ///
- /// Refer to [`http::create_channel`] for more information.
- ///
- /// Requires the [Manage Channels] permission.
- ///
- /// # Examples
- ///
- /// Create a voice channel in a guild with the name `test`:
- ///
- /// ```rust,ignore
- /// use serenity::model::ChannelType;
- ///
- /// guild.create_channel("test", ChannelType::Voice, None);
- /// ```
- ///
- /// [`GuildChannel`]: struct.GuildChannel.html
- /// [`http::create_channel`]: ../http/fn.create_channel.html
- /// [Manage Channels]: permissions/constant.MANAGE_CHANNELS.html
- #[inline]
- pub fn create_channel<C>(&self, name: &str, kind: ChannelType, category: C) -> Result<GuildChannel>
- where C: Into<Option<ChannelId>> {
- self.id.create_channel(name, kind, category)
- }
-
- /// Creates an emoji in the guild with a name and base64-encoded image.
- ///
- /// Refer to the documentation for [`Guild::create_emoji`] for more
- /// information.
- ///
- /// Requires the [Manage Emojis] permission.
- ///
- /// # Examples
- ///
- /// See the [`EditProfile::avatar`] example for an in-depth example as to
- /// how to read an image from the filesystem and encode it as base64. Most
- /// of the example can be applied similarly for this method.
- ///
- /// [`EditProfile::avatar`]: ../builder/struct.EditProfile.html#method.avatar
- /// [`Guild::create_emoji`]: struct.Guild.html#method.create_emoji
- /// [`utils::read_image`]: ../utils/fn.read_image.html
- /// [Manage Emojis]: permissions/constant.MANAGE_EMOJIS.html
- #[inline]
- pub fn create_emoji(&self, name: &str, image: &str) -> 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 [`ModelError::InvalidPermissions`]
- /// if the current user does not have permission to perform bans.
- ///
- /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
- /// [`Guild::create_role`]: struct.Guild.html#method.create_role
- /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
- #[inline]
- pub fn create_role<F: FnOnce(EditRole) -> EditRole>(&self, f: F) -> 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.
- ///
- /// **Note**: Requires the current user to have the [Manage Guild]
- /// permission.
- ///
- /// [Manage Guild]: permissions/constant.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 [`ModelError::InvalidPermissions`]
- /// if the current user does not have permission to change their own
- /// nickname.
- ///
- /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
- /// [Change Nickname]: permissions/constant.CHANGE_NICKNAME.html
- #[inline]
- pub fn edit_nickname(&self, new_nickname: Option<&str>) -> 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() }
-
- /// 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
@@ -310,77 +43,6 @@ impl PartialGuild {
.map(|icon| format!(cdn!("/icons/{}/{}.webp"), self.id, icon))
}
- /// Gets all integration of the guild.
- ///
- /// This performs a request over the REST API.
- #[inline]
- pub fn integrations(&self) -> Result<Vec<Integration>> { self.id.integrations() }
-
- /// Gets all of the guild's invites.
- ///
- /// Requires the [Manage Guild] permission.
- ///
- /// [Manage Guild]: permissions/constant.MANAGE_GUILD.html
- #[inline]
- pub fn invites(&self) -> Result<Vec<RichInvite>> { self.id.invites() }
-
- /// Leaves the guild.
- #[inline]
- pub fn leave(&self) -> Result<()> { self.id.leave() }
-
- /// Gets a user's [`Member`] for the guild by Id.
- ///
- /// [`Guild`]: struct.Guild.html
- /// [`Member`]: struct.Member.html
- pub fn member<U: Into<UserId>>(&self, user_id: U) -> Result<Member> { self.id.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 members<U>(&self, limit: Option<u64>, after: Option<U>) -> Result<Vec<Member>>
- where U: Into<UserId> {
- self.id.members(limit, after)
- }
-
- /// Moves a member to a specific voice channel.
- ///
- /// Requires the [Move Members] permission.
- ///
- /// [Move Members]: permissions/constant.MOVE_MEMBERS.html
- #[inline]
- pub fn move_member<C, U>(&self, user_id: U, channel_id: C) -> Result<()>
- where C: Into<ChannelId>, U: Into<UserId> {
- self.id.move_member(user_id, channel_id)
- }
-
- /// Gets the number of [`Member`]s that would be pruned with the given
- /// number of days.
- ///
- /// Requires the [Kick Members] permission.
- ///
- /// [`Member`]: struct.Member.html
- /// [Kick Members]: permissions/constant.KICK_MEMBERS.html
- #[inline]
- pub fn prune_count(&self, days: u16) -> Result<GuildPrune> { self.id.prune_count(days) }
-
- /// Returns the Id of the shard associated with the guild.
- ///
- /// When the cache is enabled this will automatically retrieve the total
- /// number of shards.
- ///
- /// **Note**: When the cache is enabled, this function unlocks the cache to
- /// retrieve the total number of shards in use. If you already have the
- /// total, consider using [`utils::shard_id`].
- ///
- /// [`utils::shard_id`]: ../utils/fn.shard_id.html
- #[cfg(all(feature = "cache", feature = "utils"))]
- #[inline]
- pub fn shard_id(&self) -> u64 { self.id.shard_id() }
-
/// Returns the Id of the shard associated with the guild.
///
/// When the cache is enabled this will automatically retrieve the total
@@ -401,7 +63,7 @@ impl PartialGuild {
///
/// assert_eq!(guild.shard_id(17), 7);
/// ```
- #[cfg(all(feature = "utils", not(feature = "cache")))]
+ #[cfg(feature = "utils")]
#[inline]
pub fn shard_id(&self, shard_count: u64) -> u64 { self.id.shard_id(shard_count) }
@@ -412,43 +74,6 @@ impl PartialGuild {
.map(|icon| format!(cdn!("/splashes/{}/{}.webp"), self.id, icon))
}
- /// Starts an integration sync for the given integration Id.
- ///
- /// Requires the [Manage Guild] permission.
- ///
- /// [Manage Guild]: permissions/constant.MANAGE_GUILD.html
- #[inline]
- pub fn start_integration_sync<I: 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) }
-
- /// Retrieve's the guild's vanity URL.
- ///
- /// **Note**: Requires the [Manage Guild] permission.
- ///
- /// [Manage Guild]: permissions/constant.MANAGE_GUILD.html
- #[inline]
- pub fn vanity_url(&self) -> Result<String> {
- self.id.vanity_url()
- }
-
- /// 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() }
-
/// Obtain a reference to a role by its name.
///
/// **Note**: If two or more roles have the same name, obtained reference will be one of
@@ -481,7 +106,7 @@ impl PartialGuild {
///
/// client.start().unwrap();
/// ```
- pub fn role_by_name(&self, role_name: &str) -> Option<&Role> {
- self.roles.values().find(|role| role_name == role.name)
+ pub fn role_by_name(&self, role_name: &str) -> Option<&Rc<RefCell<Role>>> {
+ self.roles.values().find(|role| role_name == role.borrow().name)
}
}
diff --git a/src/model/guild/role.rs b/src/model/guild/role.rs
index 800d178..bdc6e77 100644
--- a/src/model/guild/role.rs
+++ b/src/model/guild/role.rs
@@ -1,13 +1,6 @@
use model::prelude::*;
use std::cmp::Ordering;
-#[cfg(all(feature = "builder", feature = "cache", feature = "model"))]
-use builder::EditRole;
-#[cfg(all(feature = "cache", feature = "model"))]
-use internal::prelude::*;
-#[cfg(all(feature = "cache", feature = "model"))]
-use {CACHE, http};
-
/// Information about a role within a guild. A role represents a set of
/// permissions, and can be attached to one or multiple users. A role has
/// various miscellaneous configurations, such as being assigned a colour. Roles
@@ -59,66 +52,7 @@ pub struct Role {
pub position: i64,
}
-#[cfg(feature = "model")]
impl Role {
- /// Deletes the role.
- ///
- /// **Note** Requires the [Manage Roles] permission.
- ///
- /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
- #[cfg(feature = "cache")]
- #[inline]
- pub fn delete(&self) -> Result<()> { http::delete_role(self.find_guild()?.0, self.id.0) }
-
- /// Edits a [`Role`], optionally setting its new fields.
- ///
- /// Requires the [Manage Roles] permission.
- ///
- /// # Examples
- ///
- /// Make a role hoisted:
- ///
- /// ```rust,no_run
- /// # use serenity::model::id::RoleId;
- /// # let role = RoleId(7).find().unwrap();
- /// // assuming a `role` has already been bound
- //
- /// role.edit(|mut r| {
- /// r.hoist(true);
- ///
- /// r
- /// });
- /// ```
- ///
- /// [`Role`]: struct.Role.html
- /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
- #[cfg(all(feature = "builder", feature = "cache"))]
- pub fn edit<F: FnOnce(EditRole) -> EditRole>(&self, f: F) -> Result<Role> {
- self.find_guild()
- .and_then(|guild_id| guild_id.edit_role(self.id, f))
- }
-
- /// Searches the cache for the guild that owns the role.
- ///
- /// # Errors
- ///
- /// Returns a [`ModelError::GuildNotFound`] if a guild is not in the cache
- /// that contains the role.
- ///
- /// [`ModelError::GuildNotFound`]: enum.ModelError.html#variant.GuildNotFound
- #[cfg(feature = "cache")]
- pub fn find_guild(&self) -> Result<GuildId> {
- for guild in CACHE.read().guilds.values() {
- let guild = guild.read();
-
- if guild.roles.contains_key(&RoleId(self.id.0)) {
- return Ok(guild.id);
- }
- }
-
- Err(Error::Model(ModelError::GuildNotFound))
- }
-
/// Check that the role has the given permission.
#[inline]
pub fn has_permission(&self, permission: Permissions) -> bool {
@@ -165,29 +99,6 @@ impl PartialOrd for Role {
fn partial_cmp(&self, other: &Role) -> Option<Ordering> { Some(self.cmp(other)) }
}
-#[cfg(feature = "model")]
-impl RoleId {
- /// Search the cache for the role.
- #[cfg(feature = "cache")]
- pub fn find(&self) -> Option<Role> {
- let cache = CACHE.read();
-
- for guild in cache.guilds.values() {
- let guild = guild.read();
-
- if !guild.roles.contains_key(self) {
- continue;
- }
-
- if let Some(role) = guild.roles.get(self) {
- return Some(role.clone());
- }
- }
-
- None
- }
-}
-
impl From<Role> for RoleId {
/// Gets the Id of a role.
fn from(role: Role) -> RoleId { role.id }
diff --git a/src/model/invite.rs b/src/model/invite.rs
index 6573e35..63929e9 100644
--- a/src/model/invite.rs
+++ b/src/model/invite.rs
@@ -3,15 +3,6 @@
use chrono::{DateTime, FixedOffset};
use super::prelude::*;
-#[cfg(feature = "model")]
-use builder::CreateInvite;
-#[cfg(feature = "model")]
-use internal::prelude::*;
-#[cfg(all(feature = "cache", feature = "model"))]
-use super::{Permissions, utils as model_utils};
-#[cfg(feature = "model")]
-use {http, utils};
-
/// Information about an invite code.
///
/// Information can not be accessed for guilds the current user is banned from.
@@ -42,82 +33,7 @@ pub struct Invite {
pub guild: InviteGuild,
}
-#[cfg(feature = "model")]
impl Invite {
- /// 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 [`ModelError::InvalidPermissions`]
- /// if the current user does not have the required [permission].
- ///
- /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
- /// [`CreateInvite`]: ../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::Model(ModelError::InvalidPermissions(req)));
- }
- }
-
- let map = utils::vecmap_to_json_map(f(CreateInvite::default()).0);
-
- http::create_invite(channel_id.0, &map)
- }
-
- /// Deletes the invite.
- ///
- /// **Note**: Requires the [Manage Guild] permission.
- ///
- /// # Errors
- ///
- /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`]
- /// if the current user does not have the required [permission].
- ///
- /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
- /// [Manage Guild]: permissions/constant.MANAGE_GUILD.html
- /// [permission]: permissions/index.html
- pub fn delete(&self) -> Result<Invite> {
- #[cfg(feature = "cache")]
- {
- let req = Permissions::MANAGE_GUILD;
-
- if !model_utils::user_has_perms(self.channel.id, req)? {
- return Err(Error::Model(ModelError::InvalidPermissions(req)));
- }
- }
-
- http::delete_invite(&self.code)
- }
-
- /// Gets the information about an invite.
- #[allow(unused_mut)]
- pub fn get(code: &str, stats: bool) -> Result<Invite> {
- let mut invite = code;
-
- #[cfg(feature = "utils")]
- {
- invite = ::utils::parse_invite(invite);
- }
-
- http::get_invite(invite, stats)
- }
-
/// Returns a URL to use for the invite.
///
/// # Examples
@@ -170,27 +86,12 @@ pub struct InviteGuild {
pub voice_channel_count: Option<u64>,
}
-#[cfg(feature = "model")]
impl InviteGuild {
/// Returns the Id of the shard associated with the guild.
///
/// When the cache is enabled this will automatically retrieve the total
/// number of shards.
///
- /// **Note**: When the cache is enabled, this function unlocks the cache to
- /// retrieve the total number of shards in use. If you already have the
- /// total, consider using [`utils::shard_id`].
- ///
- /// [`utils::shard_id`]: ../utils/fn.shard_id.html
- #[cfg(all(feature = "cache", feature = "utils"))]
- #[inline]
- pub fn shard_id(&self) -> u64 { self.id.shard_id() }
-
- /// Returns the Id of the shard associated with the guild.
- ///
- /// When the cache is enabled this will automatically retrieve the total
- /// number of shards.
- ///
/// When the cache is not enabled, the total number of shards being used
/// will need to be passed.
///
@@ -206,9 +107,11 @@ impl InviteGuild {
///
/// assert_eq!(guild.shard_id(17), 7);
/// ```
- #[cfg(all(feature = "utils", not(feature = "cache")))]
+ #[cfg(feature = "utils")]
#[inline]
- pub fn shard_id(&self, shard_count: u64) -> u64 { self.id.shard_id(shard_count) }
+ pub fn shard_id(&self, shard_count: u64) -> u64 {
+ self.id.shard_id(shard_count)
+ }
}
/// Detailed information about an invite.
@@ -252,38 +155,7 @@ pub struct RichInvite {
pub uses: u64,
}
-#[cfg(feature = "model")]
impl RichInvite {
- /// Deletes the invite.
- ///
- /// Refer to [`http::delete_invite`] for more information.
- ///
- /// **Note**: Requires the [Manage Guild] permission.
- ///
- /// # Errors
- ///
- /// If the `cache` feature is enabled, then this returns a
- /// [`ModelError::InvalidPermissions`] if the current user does not have
- /// the required [permission].
- ///
- /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
- /// [`Invite::delete`]: struct.Invite.html#method.delete
- /// [`http::delete_invite`]: ../http/fn.delete_invite.html
- /// [Manage Guild]: permissions/constant.MANAGE_GUILD.html
- /// [permission]: permissions/index.html
- pub fn delete(&self) -> Result<Invite> {
- #[cfg(feature = "cache")]
- {
- let req = Permissions::MANAGE_GUILD;
-
- if !model_utils::user_has_perms(self.channel.id, req)? {
- return Err(Error::Model(ModelError::InvalidPermissions(req)));
- }
- }
-
- http::delete_invite(&self.code)
- }
-
/// Returns a URL to use for the invite.
///
/// # Examples
diff --git a/src/model/misc.rs b/src/model/misc.rs
index 5278f89..4d4fc86 100644
--- a/src/model/misc.rs
+++ b/src/model/misc.rs
@@ -1,7 +1,6 @@
//! Miscellaneous helper traits, enums, and structs for models.
use super::prelude::*;
-use internal::RwLockExt;
#[cfg(all(feature = "model", feature = "utils"))]
use std::error::Error as StdError;
@@ -28,9 +27,9 @@ impl Mentionable for ChannelId {
impl Mentionable for Channel {
fn mention(&self) -> String {
match *self {
- Channel::Guild(ref x) => format!("<#{}>", x.with(|x| x.id.0)),
- Channel::Private(ref x) => format!("<#{}>", x.with(|x| x.id.0)),
- Channel::Group(ref x) => format!("<#{}>", x.with(|x| x.channel_id.0)),
+ Channel::Guild(ref x) => format!("<#{}>", x.borrow().id.0),
+ Channel::Private(ref x) => format!("<#{}>", x.borrow().id.0),
+ Channel::Group(ref x) => format!("<#{}>", x.borrow().channel_id.0),
Channel::Category(_) => panic!("Categories can't be mentioned"),
}
}
@@ -46,10 +45,6 @@ impl Mentionable for Emoji {
fn mention(&self) -> String { format!("<:{}:{}>", self.name, self.id.0) }
}
-impl Mentionable for Member {
- fn mention(&self) -> String { format!("<@{}>", self.user.with(|u| u.id.0)) }
-}
-
impl Mentionable for RoleId {
fn mention(&self) -> String { format!("<@&{}>", self.0) }
}
@@ -90,20 +85,6 @@ impl StdError for UserParseError {
}
}
-#[cfg(all(feature = "model", feature = "utils"))]
-impl FromStr for User {
- type Err = UserParseError;
-
- fn from_str(s: &str) -> StdResult<Self, Self::Err> {
- match utils::parse_username(s) {
- Some(x) => UserId(x as u64)
- .get()
- .map_err(|e| UserParseError::Rest(Box::new(e))),
- _ => Err(UserParseError::InvalidUsername),
- }
- }
-}
-
macro_rules! impl_from_str {
(id: $($id:tt, $err:ident;)*) => {
$(
@@ -142,49 +123,6 @@ macro_rules! impl_from_str {
}
)*
};
-
- (struct: $($struct:ty, $id:tt, $err:ident, $invalid_variant:tt, $parse_fn:ident, $desc:expr;)*) => {
- $(
- #[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
- #[derive(Debug)]
- pub enum $err {
- NotPresentInCache,
- $invalid_variant,
- }
-
- #[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
- impl fmt::Display for $err {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.description()) }
- }
-
- #[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
- impl StdError for $err {
- fn description(&self) -> &str {
- use self::$err::*;
-
- match *self {
- NotPresentInCache => "not present in cache",
- $invalid_variant => $desc,
- }
- }
- }
-
- #[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
- impl FromStr for $struct {
- type Err = $err;
-
- fn from_str(s: &str) -> StdResult<Self, Self::Err> {
- match utils::$parse_fn(s) {
- Some(x) => match $id(x).find() {
- Some(user) => Ok(user),
- _ => Err($err::NotPresentInCache),
- },
- _ => Err($err::$invalid_variant),
- }
- }
- }
- )*
- };
}
impl_from_str! { id:
@@ -193,11 +131,6 @@ impl_from_str! { id:
ChannelId, ChannelIdParseError;
}
-impl_from_str! { struct:
- Channel, ChannelId, ChannelParseError, InvalidChannel, parse_channel, "invalid channel";
- Role, RoleId, RoleParseError, InvalidRole, parse_role, "invalid role";
-}
-
/// A version of an emoji used only when solely the Id and name are known.
#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub struct EmojiIdentifier {
diff --git a/src/model/mod.rs b/src/model/mod.rs
index 4416d2d..9ad7873 100644
--- a/src/model/mod.rs
+++ b/src/model/mod.rs
@@ -41,21 +41,15 @@ pub use self::error::Error as ModelError;
pub use self::permissions::Permissions;
use internal::prelude::*;
-use parking_lot::RwLock;
use self::utils::*;
use serde::de::Visitor;
+use serde::{Deserialize, Deserializer};
use std::{
collections::HashMap,
- fmt::{
- Display,
- Formatter,
- Result as FmtResult
- },
- sync::Arc,
- result::Result as StdResult
+ fmt::{Display, Formatter, Result as FmtResult},
+ rc::Rc,
+ result::Result as StdResult,
};
#[cfg(feature = "utils")]
use utils::Colour;
-
-use serde::{Deserialize, Deserializer};
diff --git a/src/model/permissions.rs b/src/model/permissions.rs
index 0076b05..3f0577f 100644
--- a/src/model/permissions.rs
+++ b/src/model/permissions.rs
@@ -260,7 +260,6 @@ __impl_bitflags! {
}
}
-#[cfg(feature = "model")]
impl Permissions {
/// Shorthand for checking that the set of permissions contains the
/// [Add Reactions] permission.
diff --git a/src/model/user.rs b/src/model/user.rs
index 131e891..86907cd 100644
--- a/src/model/user.rs
+++ b/src/model/user.rs
@@ -7,24 +7,8 @@ use super::prelude::*;
use internal::prelude::*;
use model::misc::Mentionable;
-#[cfg(all(feature = "cache", feature = "model"))]
-use CACHE;
-#[cfg(feature = "model")]
-use builder::{CreateMessage, EditProfile};
-#[cfg(feature = "model")]
use chrono::NaiveDateTime;
-#[cfg(feature = "model")]
-use http::{self, GuildPagination};
-#[cfg(all(feature = "cache", feature = "model"))]
-use parking_lot::RwLock;
-#[cfg(feature = "model")]
use std::fmt::Write;
-#[cfg(feature = "model")]
-use std::mem;
-#[cfg(all(feature = "cache", feature = "model"))]
-use std::sync::Arc;
-#[cfg(feature = "model")]
-use utils::{self, VecMap};
/// Information about the current user.
#[derive(Clone, Default, Debug, Deserialize, Serialize)]
@@ -39,7 +23,6 @@ pub struct CurrentUser {
pub verified: bool,
}
-#[cfg(feature = "model")]
impl CurrentUser {
/// Returns the formatted URL of the user's icon, if one exists.
///
@@ -71,44 +54,6 @@ impl CurrentUser {
#[inline]
pub fn default_avatar_url(&self) -> String { default_avatar_url(self.discriminator) }
- /// Edits the current user's profile settings.
- ///
- /// This mutates the current user in-place.
- ///
- /// Refer to `EditProfile`'s documentation for its methods.
- ///
- /// # Examples
- ///
- /// Change the avatar:
- ///
- /// ```rust,ignore
- /// use serenity::CACHE;
- ///
- /// let avatar = serenity::utils::read_image("./avatar.png").unwrap();
- ///
- /// CACHE.write().user.edit(|p| p.avatar(Some(&avatar)));
- /// ```
- pub fn edit<F>(&mut self, f: F) -> Result<()>
- where F: FnOnce(EditProfile) -> EditProfile {
- let mut map = VecMap::new();
- map.insert("username", Value::String(self.name.clone()));
-
- if let Some(email) = self.email.as_ref() {
- map.insert("email", Value::String(email.clone()));
- }
-
- let map = utils::vecmap_to_json_map(f(EditProfile(map)).0);
-
- match http::edit_profile(&map) {
- Ok(new) => {
- let _ = mem::replace(self, new);
-
- Ok(())
- },
- Err(why) => Err(why),
- }
- }
-
/// Retrieves the URL to the current user's avatar, falling back to the
/// default avatar if needed.
///
@@ -122,111 +67,6 @@ impl CurrentUser {
.unwrap_or_else(|| self.default_avatar_url())
}
- /// Gets a list of guilds that the current user is in.
- ///
- /// # Examples
- ///
- /// Print out the names of all guilds the current user is in:
- ///
- /// ```rust,no_run
- /// # use serenity::CACHE;
- /// #
- /// # let cache = CACHE.read();
- /// #
- /// // assuming the cache has been unlocked
- /// let user = &cache.user;
- ///
- /// if let Ok(guilds) = user.guilds() {
- /// for (index, guild) in guilds.into_iter().enumerate() {
- /// println!("{}: {}", index, guild.name);
- /// }
- /// }
- /// ```
- pub fn guilds(&self) -> Result<Vec<GuildInfo>> {
- http::get_guilds(&GuildPagination::After(GuildId(1)), 100)
- }
-
- /// Returns the invite url for the bot with the given permissions.
- ///
- /// This queries the REST API for the client id.
- ///
- /// If the permissions passed are empty, the permissions part will be dropped.
- ///
- /// # Examples
- ///
- /// Get the invite url with no permissions set:
- ///
- /// ```rust,no_run
- /// # use serenity::CACHE;
- /// #
- /// # let mut cache = CACHE.write();
- ///
- /// use serenity::model::Permissions;
- ///
- /// // assuming the cache has been unlocked
- /// let url = match cache.user.invite_url(Permissions::empty()) {
- /// Ok(v) => v,
- /// Err(why) => {
- /// println!("Error getting invite url: {:?}", why);
- ///
- /// return;
- /// },
- /// };
- ///
- /// assert_eq!(url, "https://discordapp.com/api/oauth2/authorize? \
- /// client_id=249608697955745802&scope=bot");
- /// ```
- ///
- /// Get the invite url with some basic permissions set:
- ///
- /// ```rust,no_run
- /// # use serenity::CACHE;
- /// #
- /// # let mut cache = CACHE.write();
- ///
- /// use serenity::model::Permissions;
- ///
- /// // assuming the cache has been unlocked
- /// let url = match cache.user.invite_url(Permissions::READ_MESSAGES | Permissions::SEND_MESSAGES | Permissions::EMBED_LINKS) {
- /// Ok(v) => v,
- /// Err(why) => {
- /// println!("Error getting invite url: {:?}", why);
- ///
- /// return;
- /// },
- /// };
- ///
- /// assert_eq!(url,
- /// "https://discordapp.
- /// com/api/oauth2/authorize?client_id=249608697955745802&scope=bot&permissions=19456");
- /// ```
- ///
- /// # Errors
- ///
- /// Returns an
- /// [`HttpError::InvalidRequest(Unauthorized)`][`HttpError::InvalidRequest`]
- /// If the user is not authorized for this end point.
- ///
- /// May return [`Error::Format`] while writing url to the buffer.
- ///
- /// [`Error::Format`]: ../enum.Error.html#variant.Format
- /// [`HttpError::InvalidRequest`]: ../http/enum.HttpError.html#variant.InvalidRequest
- pub fn invite_url(&self, permissions: Permissions) -> Result<String> {
- let bits = permissions.bits();
- let client_id = http::get_current_application_info().map(|v| v.id)?;
-
- let mut url = format!(
- "https://discordapp.com/api/oauth2/authorize?client_id={}&scope=bot",
- client_id
- );
-
- if bits != 0 {
- write!(url, "&permissions={}", bits)?;
- }
-
- Ok(url)
- }
-
/// Returns a static formatted URL of the user's icon, if one exists.
///
/// This will always produce a WEBP image URL.
@@ -375,7 +215,6 @@ impl Hash for User {
}
}
-#[cfg(feature = "model")]
impl User {
/// Returns the formatted URL of the user's icon, if one exists.
///
@@ -383,13 +222,6 @@ impl User {
#[inline]
pub fn avatar_url(&self) -> Option<String> { avatar_url(self.id, self.avatar.as_ref()) }
- /// Creates a direct message channel between the [current user] and the
- /// user. This can also retrieve the channel if one already exists.
- ///
- /// [current user]: struct.CurrentUser.html
- #[inline]
- pub fn create_dm_channel(&self) -> Result<PrivateChannel> { self.id.create_dm_channel() }
-
/// Retrieves the time that this user was created at.
#[inline]
pub fn created_at(&self) -> NaiveDateTime { self.id.created_at() }
@@ -400,155 +232,6 @@ impl User {
#[inline]
pub fn default_avatar_url(&self) -> String { default_avatar_url(self.discriminator) }
- /// Sends a message to a user through a direct message channel. This is a
- /// channel that can only be accessed by you and the recipient.
- ///
- /// # Examples
- ///
- /// When a user sends a message with a content of `"~help"`, DM the author a
- /// help message, and then react with `'👌'` to verify message sending:
- ///
- /// ```rust,no_run
- /// # use serenity::prelude::*;
- /// # use serenity::model::prelude::*;
- /// #
- /// use serenity::model::Permissions;
- /// use serenity::CACHE;
- ///
- /// struct Handler;
- ///
- /// impl EventHandler for Handler {
- /// fn message(&self, _: Context, msg: Message) {
- /// if msg.content == "~help" {
- /// let cache = CACHE.read();
- ///
- /// let url = match cache.user.invite_url(Permissions::empty()) {
- /// Ok(v) => v,
- /// Err(why) => {
- /// println!("Error creating invite url: {:?}", why);
- ///
- /// return;
- /// },
- /// };
- ///
- /// let help = format!(
- /// "Helpful info here. Invite me with this link: <{}>",
- /// url,
- /// );
- ///
- /// let dm = msg.author.direct_message(|mut m| {
- /// m.content(&help);
- ///
- /// m
- /// });
- ///
- /// match dm {
- /// Ok(_) => {
- /// let _ = msg.react('👌');
- /// },
- /// Err(why) => {
- /// println!("Err sending help: {:?}", why);
- ///
- /// let _ = msg.reply("There was an error DMing you help.");
- /// },
- /// };
- /// }
- /// }
- /// }
- ///
- /// let mut client = Client::new("token", Handler);
- /// ```
- ///
- /// # Examples
- ///
- /// Returns a [`ModelError::MessagingBot`] if the user being direct messaged
- /// is a bot user.
- ///
- /// [`ModelError::MessagingBot`]: enum.ModelError.html#variant.MessagingBot
- /// [`PrivateChannel`]: struct.PrivateChannel.html
- /// [`User::dm`]: struct.User.html#method.dm
- // A tale with Clippy:
- //
- // A person named Clippy once asked you to unlock a box and take something
- // from it, but you never re-locked it, so you'll die and the universe will
- // implode because the box must remain locked unless you're there, and you
- // can't just borrow that item from it and take it with you forever.
- //
- // Instead what you do is unlock the box, take the item out of it, make a
- // copy of said item, and then re-lock the box, and take your copy of the
- // item with you.
- //
- // The universe is still fine, and nothing implodes.
- //
- // (AKA: Clippy is wrong and so we have to mark as allowing this lint.)
- #[allow(let_and_return)]
- #[cfg(feature = "builder")]
- pub fn direct_message<F>(&self, f: F) -> Result<Message>
- where F: FnOnce(CreateMessage) -> CreateMessage {
- if self.bot {
- return Err(Error::Model(ModelError::MessagingBot));
- }
-
- let private_channel_id = feature_cache! {
- {
- let finding = {
- let cache = CACHE.read();
-
- let finding = cache.private_channels
- .values()
- .map(|ch| ch.read())
- .find(|ch| ch.recipient.read().id == self.id)
- .map(|ch| ch.id);
-
- finding
- };
-
- if let Some(finding) = finding {
- finding
- } else {
- let map = json!({
- "recipient_id": self.id.0,
- });
-
- http::create_private_channel(&map)?.id
- }
- } else {
- let map = json!({
- "recipient_id": self.id.0,
- });
-
- http::create_private_channel(&map)?.id
- }
- };
-
- private_channel_id.send_message(f)
- }
-
- /// This is an alias of [direct_message].
- ///
- /// # Examples
- ///
- /// Sending a message:
- ///
- /// ```rust,ignore
- /// // assuming you are in a context
- ///
- /// let _ = message.author.dm("Hello!");
- /// ```
- ///
- /// # Examples
- ///
- /// Returns a [`ModelError::MessagingBot`] if the user being direct messaged
- /// is a bot user.
- ///
- /// [`ModelError::MessagingBot`]: enum.ModelError.html#variant.MessagingBot
- /// [direct_message]: #method.direct_message
- #[cfg(feature = "builder")]
- #[inline]
- pub fn dm<F: FnOnce(CreateMessage) -> CreateMessage>(&self, f: F) -> Result<Message> {
- self.direct_message(f)
- }
-
/// Retrieves the URL to the user's avatar, falling back to the default
/// avatar if needed.
///
@@ -562,115 +245,6 @@ impl User {
.unwrap_or_else(|| self.default_avatar_url())
}
- /// Check if a user has a [`Role`]. This will retrieve the [`Guild`] from
- /// the [`Cache`] if it is available, and then check if that guild has the
- /// given [`Role`].
- ///
- /// Three forms of data may be passed in to the guild parameter: either a
- /// [`PartialGuild`], a [`GuildId`], or a `u64`.
- ///
- /// # Examples
- ///
- /// Check if a guild has a [`Role`] by Id:
- ///
- /// ```rust,ignore
- /// // Assumes a 'guild_id' and `role_id` have already been bound
- /// let _ = message.author.has_role(guild_id, role_id);
- /// ```
- ///
- /// [`Guild`]: struct.Guild.html
- /// [`GuildId`]: struct.GuildId.html
- /// [`PartialGuild`]: struct.PartialGuild.html
- /// [`Role`]: struct.Role.html
- /// [`Cache`]: ../cache/struct.Cache.html
- // no-cache would warn on guild_id.
- pub fn has_role<G, R>(&self, guild: G, role: R) -> bool
- where G: Into<GuildContainer>, R: Into<RoleId> {
- let role_id = role.into();
-
- match guild.into() {
- GuildContainer::Guild(guild) => guild.roles.contains_key(&role_id),
- GuildContainer::Id(_guild_id) => {
- feature_cache! {{
- CACHE.read()
- .guilds
- .get(&_guild_id)
- .map(|g| {
- g.read().members.get(&self.id)
- .map(|m| m.roles.contains(&role_id))
- .unwrap_or(false)
- })
- .unwrap_or(false)
- } else {
- true
- }}
- },
- }
- }
-
- /// Refreshes the information about the user.
- ///
- /// Replaces the instance with the data retrieved over the REST API.
- ///
- /// # Examples
- ///
- /// If maintaing a very long-running bot, you may want to periodically
- /// refresh information about certain users if the state becomes
- /// out-of-sync:
- ///
- /// ```rust,no_run
- /// # use serenity::prelude::*;
- /// # use serenity::model::prelude::*;
- /// #
- /// struct Handler;
- ///
- /// impl EventHandler for Handler {
- /// fn message(&self, _: Context, _: Message) {
- /// // normal message handling here
- /// }
- /// }
- ///
- /// let mut client = Client::new("token", Handler).unwrap();
- /// #
- /// use serenity::model::id::UserId;
- /// use serenity::CACHE;
- /// use std::thread;
- /// use std::time::Duration;
- ///
- /// let special_users = vec![UserId(114941315417899012), UserId(87600987040120832)];
- ///
- /// // start a new thread to periodically refresh the special users' data
- /// // every 12 hours
- /// let handle = thread::spawn(move || {
- /// // 12 hours in seconds
- /// let duration = Duration::from_secs(43200);
- ///
- /// loop {
- /// thread::sleep(duration);
- ///
- /// let cache = CACHE.read();
- ///
- /// for id in &special_users {
- /// if let Some(user) = cache.user(*id) {
- /// if let Err(why) = user.write().refresh() {
- /// println!("Error refreshing {}: {:?}", id, why);
- /// }
- /// }
- /// }
- /// }
- /// });
- ///
- /// println!("{:?}", client.start());
- /// ```
- pub fn refresh(&mut self) -> Result<()> {
- self.id.get().map(|replacement| {
- mem::replace(self, replacement);
-
- ()
- })
- }
-
-
/// Returns a static formatted URL of the user's icon, if one exists.
///
/// This will always produce a WEBP image URL.
@@ -724,64 +298,6 @@ impl fmt::Display for User {
}
}
-#[cfg(feature = "model")]
-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 = json!({
- "recipient_id": self.0,
- });
-
- http::create_private_channel(&map)
- }
-
- /// Search the cache for the user with the Id.
- #[cfg(feature = "cache")]
- pub fn find(&self) -> Option<Arc<RwLock<User>>> { CACHE.read().user(*self) }
-
- /// 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> {
- #[cfg(feature = "cache")]
- {
- if let Some(user) = CACHE.read().user(*self) {
- return Ok(user.read().clone());
- }
- }
-
- http::get_user(self.0)
- }
-}
-
-impl From<CurrentUser> for User {
- fn from(user: CurrentUser) -> Self {
- Self {
- avatar: user.avatar,
- bot: user.bot,
- discriminator: user.discriminator,
- id: user.id,
- name: user.name,
- }
- }
-}
-
-impl<'a> From<&'a CurrentUser> for User {
- fn from(user: &'a CurrentUser) -> Self {
- Self {
- avatar: user.avatar.clone(),
- bot: user.bot,
- discriminator: user.discriminator,
- id: user.id,
- name: user.name.clone(),
- }
- }
-}
-
impl From<CurrentUser> for UserId {
/// Gets the Id of a `CurrentUser` struct.
fn from(current_user: CurrentUser) -> UserId { current_user.id }
@@ -792,16 +308,6 @@ impl<'a> From<&'a CurrentUser> for UserId {
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.read().id }
-}
-
-impl<'a> From<&'a Member> for UserId {
- /// Gets the Id of a `Member`.
- fn from(member: &Member) -> UserId { member.user.read().id }
-}
-
impl From<User> for UserId {
/// Gets the Id of a `User`.
fn from(user: User) -> UserId { user.id }
@@ -812,7 +318,6 @@ impl<'a> From<&'a User> for UserId {
fn from(user: &User) -> UserId { user.id }
}
-#[cfg(feature = "model")]
fn avatar_url(user_id: UserId, hash: Option<&String>) -> Option<String> {
hash.map(|hash| {
let ext = if hash.starts_with("a_") {
@@ -825,17 +330,14 @@ fn avatar_url(user_id: UserId, hash: Option<&String>) -> Option<String> {
})
}
-#[cfg(feature = "model")]
fn default_avatar_url(discriminator: u16) -> String {
cdn!("/embed/avatars/{}.png", discriminator % 5u16)
}
-#[cfg(feature = "model")]
fn static_avatar_url(user_id: UserId, hash: Option<&String>) -> Option<String> {
hash.map(|hash| cdn!("/avatars/{}/{}.webp?size=1024", user_id, hash))
}
-#[cfg(feature = "model")]
fn tag(name: &str, discriminator: u16) -> String {
// 32: max length of username
// 1: `#`
diff --git a/src/model/utils.rs b/src/model/utils.rs
index f057047..e951edd 100644
--- a/src/model/utils.rs
+++ b/src/model/utils.rs
@@ -1,20 +1,21 @@
-use parking_lot::RwLock;
use serde::de::Error as DeError;
use serde::ser::{SerializeSeq, Serialize, Serializer};
use std::{
+ cell::RefCell,
collections::HashMap,
hash::Hash,
- sync::Arc
+ rc::Rc,
};
use super::prelude::*;
+#[cfg(all(feature = "cache", feature = "model"))]
+use cache::Cache;
+
#[cfg(feature = "cache")]
use internal::prelude::*;
#[cfg(all(feature = "cache", feature = "model"))]
use super::permissions::Permissions;
-#[cfg(all(feature = "cache", feature = "model"))]
-use CACHE;
pub fn default_true() -> bool {
true
@@ -35,12 +36,12 @@ pub fn deserialize_emojis<'de, D: Deserializer<'de>>(
pub fn deserialize_guild_channels<'de, D: Deserializer<'de>>(
deserializer: D)
- -> StdResult<HashMap<ChannelId, Arc<RwLock<GuildChannel>>>, D::Error> {
+ -> StdResult<HashMap<ChannelId, Rc<RefCell<GuildChannel>>>, D::Error> {
let vec: Vec<GuildChannel> = Deserialize::deserialize(deserializer)?;
let mut map = HashMap::new();
for channel in vec {
- map.insert(channel.id, Arc::new(RwLock::new(channel)));
+ map.insert(channel.id, Rc::new(RefCell::new(channel)));
}
Ok(map)
@@ -48,14 +49,14 @@ pub fn deserialize_guild_channels<'de, D: Deserializer<'de>>(
pub fn deserialize_members<'de, D: Deserializer<'de>>(
deserializer: D)
- -> StdResult<HashMap<UserId, Member>, D::Error> {
+ -> StdResult<HashMap<UserId, Rc<RefCell<Member>>>, D::Error> {
let vec: Vec<Member> = Deserialize::deserialize(deserializer)?;
let mut members = HashMap::new();
for member in vec {
- let user_id = member.user.read().id;
+ let user_id = member.user.borrow().id;
- members.insert(user_id, member);
+ members.insert(user_id, Rc::new(RefCell::new(member)));
}
Ok(members)
@@ -63,12 +64,12 @@ pub fn deserialize_members<'de, D: Deserializer<'de>>(
pub fn deserialize_presences<'de, D: Deserializer<'de>>(
deserializer: D)
- -> StdResult<HashMap<UserId, Presence>, D::Error> {
+ -> StdResult<HashMap<UserId, Rc<RefCell<Presence>>>, D::Error> {
let vec: Vec<Presence> = Deserialize::deserialize(deserializer)?;
let mut presences = HashMap::new();
for presence in vec {
- presences.insert(presence.user_id, presence);
+ presences.insert(presence.user_id, Rc::new(RefCell::new(presence)));
}
Ok(presences)
@@ -76,19 +77,19 @@ pub fn deserialize_presences<'de, D: Deserializer<'de>>(
pub fn deserialize_private_channels<'de, D: Deserializer<'de>>(
deserializer: D)
- -> StdResult<HashMap<ChannelId, Channel>, D::Error> {
+ -> StdResult<HashMap<ChannelId, Rc<RefCell<Channel>>>, D::Error> {
let vec: Vec<Channel> = Deserialize::deserialize(deserializer)?;
let mut private_channels = HashMap::new();
for private_channel in vec {
let id = match private_channel {
- Channel::Group(ref group) => group.read().channel_id,
- Channel::Private(ref channel) => channel.read().id,
+ Channel::Group(ref group) => group.borrow().channel_id,
+ Channel::Private(ref channel) => channel.borrow().id,
Channel::Guild(_) => unreachable!("Guild private channel decode"),
Channel::Category(_) => unreachable!("Channel category private channel decode"),
};
- private_channels.insert(id, private_channel);
+ private_channels.insert(id, Rc::new(RefCell::new(private_channel)));
}
Ok(private_channels)
@@ -96,12 +97,12 @@ pub fn deserialize_private_channels<'de, D: Deserializer<'de>>(
pub fn deserialize_roles<'de, D: Deserializer<'de>>(
deserializer: D)
- -> StdResult<HashMap<RoleId, Role>, D::Error> {
+ -> StdResult<HashMap<RoleId, Rc<RefCell<Role>>>, D::Error> {
let vec: Vec<Role> = Deserialize::deserialize(deserializer)?;
let mut roles = HashMap::new();
for role in vec {
- roles.insert(role.id, role);
+ roles.insert(role.id, Rc::new(RefCell::new(role)));
}
Ok(roles)
@@ -109,7 +110,7 @@ pub fn deserialize_roles<'de, D: Deserializer<'de>>(
pub fn deserialize_single_recipient<'de, D: Deserializer<'de>>(
deserializer: D)
- -> StdResult<Arc<RwLock<User>>, D::Error> {
+ -> StdResult<Rc<RefCell<User>>, D::Error> {
let mut users: Vec<User> = Deserialize::deserialize(deserializer)?;
let user = if users.is_empty() {
return Err(DeError::custom("Expected a single recipient"));
@@ -117,42 +118,42 @@ pub fn deserialize_single_recipient<'de, D: Deserializer<'de>>(
users.remove(0)
};
- Ok(Arc::new(RwLock::new(user)))
+ Ok(Rc::new(RefCell::new(user)))
}
-pub fn deserialize_sync_user<'de, D>(deserializer: D)
- -> StdResult<Arc<RwLock<User>>, D::Error> where D: Deserializer<'de> {
- Ok(Arc::new(RwLock::new(User::deserialize(deserializer)?)))
+pub fn deserialize_user<'de, D>(deserializer: D)
+ -> StdResult<Rc<RefCell<User>>, D::Error> where D: Deserializer<'de> {
+ Ok(Rc::new(RefCell::new(User::deserialize(deserializer)?)))
}
-pub fn serialize_sync_user<S: Serializer>(
- user: &Arc<RwLock<User>>,
+pub fn serialize_user<S: Serializer>(
+ user: &Rc<RefCell<User>>,
serializer: S,
) -> StdResult<S::Ok, S::Error> {
- User::serialize(&*user.read(), serializer)
+ User::serialize(&*user.borrow(), serializer)
}
pub fn deserialize_users<'de, D: Deserializer<'de>>(
deserializer: D)
- -> StdResult<HashMap<UserId, Arc<RwLock<User>>>, D::Error> {
+ -> StdResult<HashMap<UserId, Rc<RefCell<User>>>, D::Error> {
let vec: Vec<User> = Deserialize::deserialize(deserializer)?;
let mut users = HashMap::new();
for user in vec {
- users.insert(user.id, Arc::new(RwLock::new(user)));
+ users.insert(user.id, Rc::new(RefCell::new(user)));
}
Ok(users)
}
pub fn serialize_users<S: Serializer>(
- users: &HashMap<UserId, Arc<RwLock<User>>>,
+ users: &HashMap<UserId, Rc<RefCell<User>>>,
serializer: S
) -> StdResult<S::Ok, S::Error> {
let mut seq = serializer.serialize_seq(Some(users.len()))?;
for user in users.values() {
- seq.serialize_element(&*user.read())?;
+ seq.serialize_element(&*user.borrow())?;
}
seq.end()
@@ -192,58 +193,71 @@ pub fn serialize_gen_map<K: Eq + Hash, S: Serializer, V: Serialize>(
seq.end()
}
-pub fn serialize_gen_locked_map<K: Eq + Hash, S: Serializer, V: Serialize>(
- map: &HashMap<K, Arc<RwLock<V>>>,
+pub fn serialize_gen_rc_map<K: Eq + Hash, S: Serializer, V: Serialize>(
+ map: &HashMap<K, Rc<RefCell<V>>>,
serializer: S,
) -> StdResult<S::Ok, S::Error> {
let mut seq = serializer.serialize_seq(Some(map.len()))?;
for value in map.values() {
- seq.serialize_element(&*value.read())?;
+ if let Ok(item) = value.try_borrow() {
+ seq.serialize_element(&*item)?;
+ }
}
seq.end()
}
#[cfg(all(feature = "cache", feature = "model"))]
-pub fn user_has_perms(channel_id: ChannelId, mut permissions: Permissions) -> Result<bool> {
- let cache = CACHE.read();
- let current_user = &cache.user;
+pub trait PermissionCheck {
+ fn user_has_perms(&self, channel_id: ChannelId, permissions: Permissions)
+ -> Result<bool>;
+}
- let channel = match cache.channel(channel_id) {
- Some(channel) => channel,
- None => return Err(Error::Model(ModelError::ItemMissing)),
- };
+#[cfg(all(feature = "cache", feature = "model"))]
+impl PermissionCheck for Cache {
+ fn user_has_perms(
+ &self,
+ channel_id: ChannelId,
+ mut permissions: Permissions,
+ ) -> Result<bool> {
+ let current_user = &self.user;
+
+ let channel = match self.channel(channel_id) {
+ Some(channel) => channel,
+ None => return Err(Error::Model(ModelError::ItemMissing)),
+ };
- let guild_id = match channel {
- Channel::Guild(channel) => channel.read().guild_id,
- Channel::Group(_) | Channel::Private(_) | Channel::Category(_) => {
- // Both users in DMs, and all users in groups and maybe all channels in categories will
- // have the same
- // permissions.
- //
- // The only exception to this is when the current user is blocked by
- // the recipient in a DM channel, which results in the current user
- // not being able to send messages.
- //
- // Since serenity can't _reasonably_ check and keep track of these,
- // just assume that all permissions are granted and return `true`.
- return Ok(true);
- },
- };
+ let guild_id = match channel {
+ Channel::Guild(channel) => channel.borrow().guild_id,
+ Channel::Group(_) | Channel::Private(_) | Channel::Category(_) => {
+ // Both users in DMs, and all users in groups and maybe all channels in categories will
+ // have the same
+ // permissions.
+ //
+ // The only exception to this is when the current user is blocked by
+ // the recipient in a DM channel, which results in the current user
+ // not being able to send messages.
+ //
+ // Since serenity can't _reasonably_ check and keep track of these,
+ // just assume that all permissions are granted and return `true`.
+ return Ok(true);
+ },
+ };
- let guild = match cache.guild(guild_id) {
- Some(guild) => guild,
- None => return Err(Error::Model(ModelError::ItemMissing)),
- };
+ let guild = match self.guilds.get(&guild_id) {
+ Some(guild) => guild,
+ None => return Err(Error::Model(ModelError::ItemMissing)),
+ };
- let perms = guild
- .read()
- .permissions_in(channel_id, current_user.id);
+ let perms = guild
+ .borrow()
+ .permissions_in(channel_id, current_user.id);
- permissions.remove(perms);
+ permissions.remove(perms);
- Ok(permissions.is_empty())
+ Ok(permissions.is_empty())
+ }
}
macro_rules! num_visitors {
diff --git a/src/model/webhook.rs b/src/model/webhook.rs
index 8f2c6b2..511a283 100644
--- a/src/model/webhook.rs
+++ b/src/model/webhook.rs
@@ -2,24 +2,13 @@
use super::{
id::{
- ChannelId,
- GuildId,
+ ChannelId,
+ GuildId,
WebhookId
},
user::User
};
-#[cfg(feature = "model")]
-use builder::ExecuteWebhook;
-#[cfg(feature = "model")]
-use internal::prelude::*;
-#[cfg(feature = "model")]
-use std::mem;
-#[cfg(feature = "model")]
-use super::channel::Message;
-#[cfg(feature = "model")]
-use {http, utils};
-
/// A representation of a webhook, which is a low-effort way to post messages to
/// channels. They do not necessarily require a bot user or authentication to
/// use.
@@ -52,188 +41,3 @@ pub struct Webhook {
/// **Note**: This is not received when getting a webhook by its token.
pub user: Option<User>,
}
-
-#[cfg(feature = "model")]
-impl Webhook {
- /// Deletes the webhook.
- ///
- /// As this calls the [`http::delete_webhook_with_token`] function,
- /// authentication is not required.
- ///
- /// [`http::delete_webhook_with_token`]: ../http/fn.delete_webhook_with_token.html
- #[inline]
- pub fn delete(&self) -> Result<()> { http::delete_webhook_with_token(self.id.0, &self.token) }
-
- ///
- /// Edits the webhook in-place. All fields are optional.
- ///
- /// To nullify the avatar, pass `Some("")`. Otherwise, passing `None` will
- /// not modify the avatar.
- ///
- /// Refer to [`http::edit_webhook`] for httprictions on editing webhooks.
- ///
- /// As this calls the [`http::edit_webhook_with_token`] function,
- /// authentication is not required.
- ///
- /// # Examples
- ///
- /// Editing a webhook's name:
- ///
- /// ```rust,no_run
- /// use serenity::http;
- ///
- /// let id = 245037420704169985;
- /// let token = "ig5AO-wdVWpCBtUUMxmgsWryqgsW3DChbKYOINftJ4DCrUbnkedoYZD0VOH1QLr-S3sV";
- ///
- /// let mut webhook = http::get_webhook_with_token(id, token)
- /// .expect("valid webhook");
- ///
- /// let _ = webhook.edit(Some("new name"), None).expect("Error editing");
- /// ```
- ///
- /// Setting a webhook's avatar:
- ///
- /// ```rust,no_run
- /// use serenity::http;
- ///
- /// let id = 245037420704169985;
- /// let token = "ig5AO-wdVWpCBtUUMxmgsWryqgsW3DChbKYOINftJ4DCrUbnkedoYZD0VOH1QLr-S3sV";
- ///
- /// let mut webhook = http::get_webhook_with_token(id, token)
- /// .expect("valid webhook");
- ///
- /// let image = serenity::utils::read_image("./webhook_img.png")
- /// .expect("Error reading image");
- ///
- /// let _ = webhook.edit(None, Some(&image)).expect("Error editing");
- /// ```
- ///
- /// [`http::edit_webhook`]: ../http/fn.edit_webhook.html
- /// [`http::edit_webhook_with_token`]: ../http/fn.edit_webhook_with_token.html
- pub fn edit(&mut self, name: Option<&str>, avatar: Option<&str>) -> Result<()> {
- if name.is_none() && avatar.is_none() {
- return Ok(());
- }
-
- let mut map = Map::new();
-
- if let Some(avatar) = avatar {
- map.insert(
- "avatar".to_string(),
- if avatar.is_empty() {
- Value::Null
- } else {
- Value::String(avatar.to_string())
- },
- );
- }
-
- if let Some(name) = name {
- map.insert("name".to_string(), Value::String(name.to_string()));
- }
-
- match http::edit_webhook_with_token(self.id.0, &self.token, &map) {
- Ok(replacement) => {
- mem::replace(self, replacement);
-
- Ok(())
- },
- Err(why) => Err(why),
- }
- }
-
- /// Executes a webhook with the fields set via the given builder.
- ///
- /// The builder provides a method of setting only the fields you need,
- /// without needing to pass a long set of arguments.
- ///
- /// # Examples
- ///
- /// Execute a webhook with message content of `test`:
- ///
- /// ```rust,no_run
- /// use serenity::http;
- ///
- /// let id = 245037420704169985;
- /// let token = "ig5AO-wdVWpCBtUUMxmgsWryqgsW3DChbKYOINftJ4DCrUbnkedoYZD0VOH1QLr-S3sV";
- ///
- /// let mut webhook = http::get_webhook_with_token(id, token)
- /// .expect("valid webhook");
- ///
- /// let _ = webhook.execute(false, |mut w| {
- /// w.content("test");
- ///
- /// w
- /// });
- /// ```
- ///
- /// Execute a webhook with message content of `test`, overriding the
- /// username to `serenity`, and sending an embed:
- ///
- /// ```rust,no_run
- /// use serenity::http;
- /// use serenity::model::channel::Embed;
- ///
- /// let id = 245037420704169985;
- /// let token = "ig5AO-wdVWpCBtUUMxmgsWryqgsW3DChbKYOINftJ4DCrUbnkedoYZD0VOH1QLr-S3sV";
- ///
- /// let mut webhook = http::get_webhook_with_token(id, token)
- /// .expect("valid webhook");
- ///
- /// let embed = Embed::fake(|mut e| {
- /// e.title("Rust's website");
- /// e.description("Rust is a systems programming language that runs
- /// blazingly fast, prevents segfaults, and guarantees
- /// thread safety.");
- /// e.url("https://rust-lang.org");
- ///
- /// e
- /// });
- ///
- /// let _ = webhook.execute(false, |mut w| {
- /// w.content("test");
- /// w.username("serenity");
- /// w.embeds(vec![embed]);
- ///
- /// w
- /// });
- /// ```
- #[inline]
- pub fn execute<F: FnOnce(ExecuteWebhook) -> ExecuteWebhook>(&self,
- wait: bool,
- f: F)
- -> Result<Option<Message>> {
- let map = utils::vecmap_to_json_map(f(ExecuteWebhook::default()).0);
-
- http::execute_webhook(self.id.0, &self.token, wait, &map)
- }
-
- /// Retrieves the latest information about the webhook, editing the
- /// webhook in-place.
- ///
- /// As this calls the [`http::get_webhook_with_token`] function,
- /// authentication is not required.
- ///
- /// [`http::get_webhook_with_token`]: ../http/fn.get_webhook_with_token.html
- pub fn refresh(&mut self) -> Result<()> {
- match http::get_webhook_with_token(self.id.0, &self.token) {
- Ok(replacement) => {
- let _ = mem::replace(self, replacement);
-
- Ok(())
- },
- Err(why) => Err(why),
- }
- }
-}
-
-#[cfg(feature = "model")]
-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> { http::get_webhook(self.0) }
-}