diff options
| author | Zeyla Hellyer <[email protected]> | 2018-03-25 19:24:19 -0700 |
|---|---|---|
| committer | Zeyla Hellyer <[email protected]> | 2018-03-25 19:24:19 -0700 |
| commit | 461ebe03d58d1ec78ed5addb65e688d63ecfcf45 (patch) | |
| tree | 84475e0717d089551b7e615cdf7d2cfcbff32d57 /src/model/guild | |
| parent | Rewrite the library to use Futures (diff) | |
| download | serenity-461ebe03d58d1ec78ed5addb65e688d63ecfcf45.tar.xz serenity-461ebe03d58d1ec78ed5addb65e688d63ecfcf45.zip | |
Remove cache/http methods on structs
Diffstat (limited to 'src/model/guild')
| -rw-r--r-- | src/model/guild/emoji.rs | 139 | ||||
| -rw-r--r-- | src/model/guild/guild_id.rs | 1 | ||||
| -rw-r--r-- | src/model/guild/member.rs | 384 | ||||
| -rw-r--r-- | src/model/guild/mod.rs | 819 | ||||
| -rw-r--r-- | src/model/guild/partial_guild.rs | 406 | ||||
| -rw-r--r-- | src/model/guild/role.rs | 74 |
6 files changed, 4 insertions, 1819 deletions
diff --git a/src/model/guild/emoji.rs b/src/model/guild/emoji.rs index 48d9b7d..08f63ef 100644 --- a/src/model/guild/emoji.rs +++ b/src/model/guild/emoji.rs @@ -1,17 +1,5 @@ use std::fmt::{Display, Formatter, Result as FmtResult, Write as FmtWrite}; use super::super::id::{EmojiId, RoleId}; -use super::super::WrappedClient; - -#[cfg(feature = "cache")] -use futures::{Future, future}; -#[cfg(all(feature = "cache", feature = "model"))] -use internal::prelude::*; -#[cfg(all(feature = "cache", feature = "model"))] -use super::super::ModelError; -#[cfg(all(feature = "cache", feature = "model"))] -use super::super::id::GuildId; -#[cfg(feature = "cache")] -use ::FutureResult; /// Represents a custom guild emoji, which can either be created using the API, /// or via an integration. Emojis created using the API only work within the @@ -38,136 +26,9 @@ pub struct Emoji { /// /// [`Role`]: struct.Role.html pub roles: Vec<RoleId>, - #[serde(skip)] - pub(crate) client: WrappedClient, } -#[cfg(feature = "model")] impl Emoji { - /// Deletes the emoji. - /// - /// **Note**: The [Manage Emojis] permission is required. - /// - /// **Note**: Only user accounts may use this method. - /// - /// [Manage Emojis]: permissions/constant.MANAGE_EMOJIS.html - /// - /// # Examples - /// - /// Delete a given emoji: - /// - /// ```rust,no_run - /// # use serenity::model::guild::Emoji; - /// # use serenity::model::id::EmojiId; - /// # - /// # let mut emoji = Emoji { - /// # animated: false, - /// # id: EmojiId(7), - /// # name: String::from("blobface"), - /// # managed: false, - /// # require_colons: false, - /// # roles: vec![], - /// # }; - /// # - /// // assuming emoji has been set already - /// match emoji.delete() { - /// Ok(()) => println!("Emoji deleted."), - /// Err(_) => println!("Could not delete emoji.") - /// } - /// ``` - #[cfg(feature = "cache")] - pub fn delete(&self) -> FutureResult<()> { - let guild_id = match self.find_guild_id() { - Some(guild_id) => guild_id, - None => return Box::new(future::err(Error::Model( - ModelError::ItemMissing, - ))), - }; - - ftryopt!(self.client).http.delete_emoji(guild_id.0, self.id.0) - } - - /// Edits the emoji by updating it with a new name. - /// - /// **Note**: The [Manage Emojis] permission is required. - /// - /// **Note**: Only user accounts may use this method. - /// - /// [Manage Emojis]: permissions/constant.MANAGE_EMOJIS.html - /// - /// # Examples - /// - /// Change the name of an emoji: - /// - /// ```rust,no_run - /// # use serenity::model::guild::Emoji; - /// # use serenity::model::id::EmojiId; - /// # - /// # let mut emoji = Emoji { - /// # animated: false, - /// # id: EmojiId(7), - /// # name: String::from("blobface"), - /// # managed: false, - /// # require_colons: false, - /// # roles: vec![], - /// # }; - /// # - /// // assuming emoji has been set already - /// let _ = emoji.edit("blobuwu"); - /// assert_eq!(emoji.name, "blobuwu"); - /// ``` - #[cfg(feature = "cache")] - pub fn edit<'a>(&'a mut self, name: &'a str) - -> Box<Future<Item = Emoji, Error = Error> + 'a> { - let guild_id = match self.find_guild_id() { - Some(guild_id) => guild_id, - None => return Box::new(future::err(Error::Model( - ModelError::ItemMissing, - ))), - }; - - ftryopt!(self.client).http.edit_emoji(guild_id.0, self.id.0, name) - } - - /// Finds the [`Guild`] that owns the emoji by looking through the Cache. - /// - /// [`Guild`]: struct.Guild.html - /// - /// # Examples - /// - /// Print the guild id that owns this emoji: - /// - /// ```rust,no_run - /// # use serenity::model::guild::Emoji; - /// # use serenity::model::id::EmojiId; - /// # - /// # let mut emoji = Emoji { - /// # animated: false, - /// # id: EmojiId(7), - /// # name: String::from("blobface"), - /// # managed: false, - /// # require_colons: false, - /// # roles: vec![], - /// # }; - /// # - /// // assuming emoji has been set already - /// if let Some(guild_id) = emoji.find_guild_id() { - /// println!("{} is owned by {}", emoji.name, guild_id); - /// } - /// ``` - #[cfg(feature = "cache")] - pub fn find_guild_id(&self) -> Option<GuildId> { - for guild in self.client.as_ref()?.cache.borrow().guilds.values() { - let guild = guild.borrow(); - - if guild.emojis.contains_key(&self.id) { - return Some(guild.id); - } - } - - None - } - /// Generates a URL to the emoji's image. /// /// # Examples diff --git a/src/model/guild/guild_id.rs b/src/model/guild/guild_id.rs index ea095a0..eacf07e 100644 --- a/src/model/guild/guild_id.rs +++ b/src/model/guild/guild_id.rs @@ -1,6 +1,5 @@ use model::prelude::*; -#[cfg(feature = "model")] impl GuildId { /// Converts the guild Id into the default channel's Id. #[inline] diff --git a/src/model/guild/member.rs b/src/model/guild/member.rs index 0c22597..bc8e27e 100644 --- a/src/model/guild/member.rs +++ b/src/model/guild/member.rs @@ -1,19 +1,8 @@ use chrono::{DateTime, FixedOffset}; -use futures::future; use model::prelude::*; +use std::borrow::Cow; use std::cell::RefCell; -use super::super::WrappedClient; use super::deserialize_user; -use ::FutureResult; - -#[cfg(all(feature = "builder", feature = "cache", feature = "model"))] -use builder::EditMember; -#[cfg(all(feature = "cache", feature = "model"))] -use internal::prelude::*; -#[cfg(feature = "model")] -use std::borrow::Cow; -#[cfg(all(feature = "cache", feature = "model", feature = "utils"))] -use utils::Colour; /// A trait for allowing both u8 or &str or (u8, &str) to be passed into the `ban` methods in `Guild` and `Member`. pub trait BanOptions { @@ -70,132 +59,9 @@ pub struct Member { #[serde(deserialize_with = "deserialize_user", serialize_with = "serialize_user")] pub user: Rc<RefCell<User>>, - #[serde(skip)] - pub(crate) client: WrappedClient, } -#[cfg(feature = "model")] impl Member { - /// Adds a [`Role`] to the member. - /// - /// **Note**: Requires the [Manage Roles] permission. - /// - /// [`Role`]: struct.Role.html - /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html - #[cfg(feature = "cache")] - pub fn add_role<R: Into<RoleId>>(&mut self, role_id: R) - -> FutureResult<()> { - let role_id = role_id.into(); - - if self.roles.contains(&role_id) { - return Box::new(future::ok(())); - } - - ftryopt!(self.client).http.add_member_role( - self.guild_id.0, - self.user.borrow().id.0, - role_id.0, - ) - } - - /// Adds one or multiple [`Role`]s to the member. - /// - /// **Note**: Requires the [Manage Roles] permission. - /// - /// [`Role`]: struct.Role.html - /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html - #[cfg(feature = "cache")] - pub fn add_roles(&mut self, role_ids: &[RoleId]) -> FutureResult<()> { - let mut roles = self.roles.clone(); - roles.extend(role_ids); - - ftryopt!(self.client).http.edit_member( - self.guild_id.0, - self.user.borrow().id.0, - |f| f.roles(roles), - ) - } - - /// Ban the member from its guild, deleting the last X number of - /// days' worth of messages. - /// - /// **Note**: Requires the [Ban Members] permission. - /// - /// # Errors - /// - /// Returns a [`ModelError::GuildNotFound`] if the guild could not be - /// found. - /// - /// [`ModelError::GuildNotFound`]: enum.ModelError.html#variant.GuildNotFound - /// - /// [Ban Members]: permissions/constant.BAN_MEMBERS.html - #[cfg(feature = "cache")] - pub fn ban<BO: BanOptions>(&self, ban_options: &BO) -> FutureResult<()> { - let dmd = ban_options.dmd(); - - if dmd > 7 { - return Box::new(future::err(Error::Model( - ModelError::DeleteMessageDaysAmount(dmd), - ))); - } - - let reason = ban_options.reason(); - - if reason.len() > 512 { - return Box::new(future::err(Error::ExceededLimit( - reason.to_string(), - 512, - ))); - } - - ftryopt!(self.client).http.ban_user( - self.guild_id.0, - self.user.borrow().id.0, - dmd, - &*reason, - ) - } - - /// Determines the member's colour. - #[cfg(all(feature = "cache", feature = "utils"))] - pub fn colour(&self) -> Option<Colour> { - let client = self.client.as_ref()?; - let cache = client.cache.try_borrow().ok()?; - let guild = cache.guild(self.guild_id)?; - let guild = guild.borrow(); - - let mut roles = self.roles - .iter() - .filter_map(|role_id| guild.roles.get(role_id)) - .collect::<Vec<&Rc<RefCell<Role>>>>(); - roles.sort_by(|a, b| b.cmp(a)); - - let default = Colour::default(); - - roles - .iter() - .find(|r| r.borrow().colour.0 != default.0) - .map(|r| r.borrow().colour) - } - - /// Returns the "default channel" of the guild for the member. - /// (This returns the first channel that can be read by the member, if there isn't - /// one returns `None`) - #[cfg(feature = "cache")] - pub fn default_channel(&self) -> Option<Rc<RefCell<GuildChannel>>> { - let cache = self.client.as_ref()?.cache.borrow(); - let guild = cache.guild(self.guild_id)?; - let reader = guild.borrow(); - - for (cid, channel) in &reader.channels { - if reader.permissions_in(*cid, self.user.borrow().id).read_messages() { - return Some(Rc::clone(channel)); - } - } - - None - } - /// Calculates the member's display name. /// /// The nickname takes priority over the member's username if it exists. @@ -222,252 +88,4 @@ impl Member { ) } } - - /// Edits the member with the given data. See [`Guild::edit_member`] for - /// more information. - /// - /// See [`EditMember`] for the permission(s) required for separate builder - /// methods, as well as usage of this. - /// - /// [`Guild::edit_member`]: ../model/guild/struct.Guild.html#method.edit_member - /// [`EditMember`]: ../builder/struct.EditMember.html - #[cfg(feature = "cache")] - pub fn edit<F: FnOnce(EditMember) -> EditMember>(&self, f: F) - -> FutureResult<()> { - ftryopt!(self.client).http.edit_member( - self.guild_id.0, - self.user.borrow().id.0, - f, - ) - } - - /// Retrieves the ID and position of the member's highest role in the - /// hierarchy, if they have one. - /// - /// This _may_ return `None` if the user has roles, but they are not present - /// in the cache for cache inconsistency reasons. - /// - /// The "highest role in hierarchy" is defined as the role with the highest - /// position. If two or more roles have the same highest position, then the - /// role with the lowest ID is the highest. - /// - /// # Deadlocking - /// - /// This function will deadlock if you have a write lock to the member's - /// guild. - #[cfg(feature = "cache")] - pub fn highest_role_info(&self) -> Option<(RoleId, i64)> { - let cache = self.client.as_ref()?.cache.try_borrow().ok()?; - let guild = cache.guild(self.guild_id)?; - let reader = guild.borrow(); - - let mut highest = None; - - for role_id in &self.roles { - let role = reader.roles - .get(&role_id) - .and_then(|x| x.try_borrow().ok()); - - if let Some(role) = role { - // Skip this role if this role in iteration has: - // - // - a position less than the recorded highest - // - a position equal to the recorded, but a higher ID - if let Some((id, pos)) = highest { - if role.position < pos || (role.position == pos && role.id > id) { - continue; - } - } - - highest = Some((role.id, role.position)); - } - } - - highest - } - - /// Kick the member from the guild. - /// - /// **Note**: Requires the [Kick Members] permission. - /// - /// # Examples - /// - /// Kick a member from its guild: - /// - /// ```rust,ignore - /// // assuming a `member` has already been bound - /// match member.kick() { - /// Ok(()) => println!("Successfully kicked member"), - /// Err(Error::Model(ModelError::GuildNotFound)) => { - /// println!("Couldn't determine guild of member"); - /// }, - /// Err(Error::Model(ModelError::InvalidPermissions(missing_perms))) => { - /// println!("Didn't have permissions; missing: {:?}", missing_perms); - /// }, - /// _ => {}, - /// } - /// ``` - /// - /// # Errors - /// - /// Returns a [`ModelError::GuildNotFound`] if the Id of the member's guild - /// could not be determined. - /// - /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`] - /// if the current user does not have permission to perform the kick. - /// - /// [`ModelError::GuildNotFound`]: enum.ModelError.html#variant.GuildNotFound - /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions - /// [Kick Members]: permissions/constant.KICK_MEMBERS.html - pub fn kick(&self) -> FutureResult<()> { - let client = ftryopt!(self.client); - - #[cfg(feature = "cache")] - { - let cache = ftry!(client.cache.try_borrow()); - - if let Some(guild) = cache.guilds.get(&self.guild_id) { - let req = Permissions::KICK_MEMBERS; - let reader = ftry!(guild.try_borrow()); - - if !reader.has_perms(req) { - return Box::new(future::err(Error::Model( - ModelError::InvalidPermissions(req), - ))); - } - - ftry!(reader.check_hierarchy(ftry!(self.user.try_borrow()).id)); - } - } - - let user_id = ftry!(self.user.try_borrow()).id.0; - - ftryopt!(self.client).http.kick_member(self.guild_id.0, user_id) - } - - /// Returns the guild-level permissions for the member. - /// - /// # Examples - /// - /// ```rust,ignore - /// // assuming there's a `member` variable gotten from anything. - /// println!("The permission bits for the member are: {}", - /// member.permissions().expect("permissions").bits); - /// ``` - /// - /// # Errors - /// - /// Returns a [`ModelError::GuildNotFound`] if the guild the member's in could not be - /// found in the cache. - /// - /// And/or returns [`ModelError::ItemMissing`] if the "default channel" of the guild is not - /// found. - /// - /// [`ModelError::GuildNotFound`]: enum.ModelError.html#variant.GuildNotFound - /// [`ModelError::ItemMissing`]: enum.ModelError.html#variant.ItemMissing - #[cfg(feature = "cache")] - pub fn permissions(&self) -> Result<Permissions> { - let client = self.client.as_ref().ok_or_else(|| { - Error::Model(ModelError::ClientNotPresent) - })?; - let cache = client.cache.try_borrow()?; - let guild = match cache.guilds.get(&self.guild_id) { - Some(guild) => guild, - None => return Err(From::from(ModelError::GuildNotFound)), - }; - - let guild = guild.try_borrow()?; - - Ok(guild.member_permissions(self.user.try_borrow()?.id)) - } - - /// Removes a [`Role`] from the member. - /// - /// **Note**: Requires the [Manage Roles] permission. - /// - /// [`Role`]: struct.Role.html - /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html - #[cfg(feature = "cache")] - pub fn remove_role<R: Into<RoleId>>(&mut self, role_id: R) -> FutureResult<()> { - let role_id = role_id.into(); - - if !self.roles.contains(&role_id) { - return Box::new(future::ok(())); - } - - ftryopt!(self.client).http.remove_member_role( - self.guild_id.0, - self.user.borrow().id.0, - role_id.0, - ) - } - - /// Removes one or multiple [`Role`]s from the member. - /// - /// **Note**: Requires the [Manage Roles] permission. - /// - /// [`Role`]: struct.Role.html - /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html - #[cfg(feature = "cache")] - pub fn remove_roles(&mut self, role_ids: &[RoleId]) -> FutureResult<()> { - let mut roles = self.roles.clone(); - roles.retain(|r| !role_ids.contains(r)); - - ftryopt!(self.client).http.edit_member( - self.guild_id.0, - self.user.borrow().id.0, - |f| f.roles(roles), - ) - } - - /// Retrieves the full role data for the user's roles. - /// - /// This is shorthand for manually searching through the CACHE. - /// - /// If role data can not be found for the member, then `None` is returned. - #[cfg(feature = "cache")] - pub fn roles(&self) -> Option<Vec<Rc<RefCell<Role>>>> { - let client = self.client.as_ref()?; - let cache = client.cache.try_borrow().ok()?; - - cache.guilds.get(&self.guild_id).and_then(|guild| { - let guild = guild.try_borrow().ok()?; - - let roles = guild - .roles - .values() - .filter(|role| { - let role = match role.try_borrow() { - Ok(role) => role, - Err(_) => return false, - }; - - self.roles.contains(&role.id) - }) - .cloned() - .collect(); - - Some(roles) - }) - } - - /// Unbans the [`User`] from the guild. - /// - /// **Note**: Requires the [Ban Members] permission. - /// - /// # Errors - /// - /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`] - /// if the current user does not have permission to perform bans. - /// - /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions - /// [`User`]: struct.User.html - /// [Ban Members]: permissions/constant.BAN_MEMBERS.html - #[cfg(feature = "cache")] - pub fn unban(&self) -> FutureResult<()> { - ftryopt!(self.client).http.remove_ban( - self.guild_id.0, - self.user.borrow().id.0, - ) - } } diff --git a/src/model/guild/mod.rs b/src/model/guild/mod.rs index 6c0fa82..d2281e9 100644 --- a/src/model/guild/mod.rs +++ b/src/model/guild/mod.rs @@ -17,24 +17,15 @@ pub use self::role::*; pub use self::audit_log::*; use chrono::{DateTime, FixedOffset}; -use futures::{Future, future}; +use constants::LARGE_THRESHOLD; use model::prelude::*; use serde::de::Error as DeError; use serde_json; +use std::borrow::Cow; use std::cell::RefCell; use std::rc::Rc; -use super::utils::*; -use super::WrappedClient; -use ::FutureResult; - -#[cfg(feature = "model")] -use builder::{EditGuild, EditMember, EditRole}; -#[cfg(feature = "model")] -use constants::LARGE_THRESHOLD; -#[cfg(feature = "model")] use std; -#[cfg(feature = "model")] -use std::borrow::Cow; +use super::utils::*; /// A representation of a banning of a user. #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Hash, Serialize)] @@ -143,29 +134,9 @@ pub struct Guild { /// [`User`]: struct.User.html #[serde(serialize_with = "serialize_gen_map")] pub voice_states: HashMap<UserId, VoiceState>, - #[serde(skip)] - pub(crate) client: WrappedClient, } -#[cfg(feature = "model")] impl Guild { - #[cfg(feature = "cache")] - fn check_hierarchy(&self, other_user: UserId) -> Result<()> { - let client = self.client.as_ref().ok_or_else(|| { - Error::Model(ModelError::ClientNotPresent) - })?; - - let current_id = client.cache.try_borrow()?.user.id; - - if let Some(higher) = self.greater_member_hierarchy(other_user, current_id) { - if higher != current_id { - return Err(Error::Model(ModelError::Hierarchy)); - } - } - - Ok(()) - } - /// Returns the "default" channel of the guild for the passed user id. /// (This returns the first channel that can be read by the user, if there isn't one, /// returns `None`) @@ -196,569 +167,6 @@ impl Guild { None } - #[cfg(feature = "cache")] - fn has_perms(&self, mut permissions: Permissions) -> bool { - let client = match self.client.as_ref() { - Some(client) => client, - None => return true, - }; - let cache = match client.cache.try_borrow() { - Ok(cache) => cache, - Err(_) => return true, - }; - - let user_id = cache.user.id; - - let perms = self.member_permissions(user_id); - permissions.remove(perms); - - permissions.is_empty() - } - - /// Ban a [`User`] from the guild. All messages by the - /// user within the last given number of days given will be deleted. - /// - /// Refer to the documentation for [`Guild::ban`] for more information. - /// - /// **Note**: Requires the [Ban Members] permission. - /// - /// # Examples - /// - /// Ban a member and remove all messages they've sent in the last 4 days: - /// - /// ```rust,ignore - /// // assumes a `user` and `guild` have already been bound - /// let _ = guild.ban(user, 4); - /// ``` - /// - /// # Errors - /// - /// Returns a [`ModelError::InvalidPermissions`] if the current user does - /// not have permission to perform bans. - /// - /// Returns a [`ModelError::DeleteMessageDaysAmount`] if the number of - /// days' worth of messages to delete is over the maximum. - /// - /// [`ModelError::DeleteMessageDaysAmount`]: - /// enum.ModelError.html#variant.DeleteMessageDaysAmount - /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions - /// [`Guild::ban`]: struct.Guild.html#method.ban - /// [`User`]: struct.User.html - /// [Ban Members]: permissions/constant.BAN_MEMBERS.html - pub fn ban<U: Into<UserId>, BO: BanOptions>(&self, user: U, options: &BO) - -> FutureResult<()> { - let user = user.into(); - - #[cfg(feature = "cache")] - { - let req = Permissions::BAN_MEMBERS; - - if !self.has_perms(req) { - return Box::new(future::err(Error::Model( - ModelError::InvalidPermissions(req), - ))); - } - - ftry!(self.check_hierarchy(user)); - } - - let dmd = options.dmd(); - if dmd > 7 { - return Box::new(future::err(Error::Model( - ModelError::DeleteMessageDaysAmount(dmd), - ))); - } - - let reason = options.reason(); - - if reason.len() > 512 { - return Box::new(future::err(Error::ExceededLimit( - reason.to_string(), - 512, - ))); - } - - ftryopt!(self.client) - .http - .ban_user(self.id.0, user.0, dmd, reason) - } - - /// Retrieves a list of [`Ban`]s for the guild. - /// - /// **Note**: Requires the [Ban Members] permission. - /// - /// # Errors - /// - /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`] - /// if the current user does not have permission to perform bans. - /// - /// [`Ban`]: struct.Ban.html - /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions - /// [Ban Members]: permissions/constant.BAN_MEMBERS.html - pub fn bans(&self) -> FutureResult<Vec<Ban>> { - #[cfg(feature = "cache")] - { - let req = Permissions::BAN_MEMBERS; - - if !self.has_perms(req) { - return Box::new(future::err(Error::Model( - ModelError::InvalidPermissions(req), - ))); - } - } - - ftryopt!(self.client).http.get_bans(self.id.0) - } - - /// Retrieves a list of [`AuditLogs`] for the guild. - /// - /// [`AuditLogs`]: audit_log/struct.AuditLogs.html - #[inline] - pub fn audit_logs( - &self, - action_type: Option<u8>, - user_id: Option<UserId>, - before: Option<AuditLogEntryId>, - limit: Option<u8>, - ) -> FutureResult<AuditLogs> { - ftryopt!(self.client).http.get_audit_logs( - self.id.0, - action_type, - user_id.map(|x| x.0), - before.map(|x| x.0), - limit, - ) - } - - /// Gets all of the guild's channels over the REST API. - /// - /// [`Guild`]: struct.Guild.html - #[inline] - pub fn channels(&self) -> FutureResult<HashMap<ChannelId, GuildChannel>> { - let done = ftryopt!(self.client) - .http - .get_channels(self.id.0) - .map(|channels| { - let mut map = HashMap::with_capacity(channels.len()); - - for channel in channels { - map.insert(channel.id, channel); - } - - map - }); - - Box::new(done) - } - - /// Creates a new [`Channel`] in the guild. - /// - /// **Note**: Requires the [Manage Channels] permission. - /// - /// # Examples - /// - /// ```rust,ignore - /// use serenity::model::ChannelType; - /// - /// // assuming a `guild` has already been bound - /// - /// let _ = guild.create_channel("my-test-channel", ChannelType::Text, None); - /// ``` - /// - /// # Errors - /// - /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`] - /// if the current user does not have permission to perform bans. - /// - /// [`Channel`]: struct.Channel.html - /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions - /// [Manage Channels]: permissions/constant.MANAGE_CHANNELS.html - pub fn create_channel<C>(&self, name: &str, kind: ChannelType, category: C) - -> FutureResult<GuildChannel> where C: Into<Option<ChannelId>> { - #[cfg(feature = "cache")] - { - let req = Permissions::MANAGE_CHANNELS; - - if !self.has_perms(req) { - return Box::new(future::err(Error::Model( - ModelError::InvalidPermissions(req), - ))); - } - } - - ftryopt!(self.client).http.create_channel( - self.id.0, - name, - kind, - category.into().map(|x| x.0), - ) - } - - /// Creates an emoji in the guild with a name and base64-encoded image. The - /// [`utils::read_image`] function is provided for you as a simple method to - /// read an image and encode it into base64, if you are reading from the - /// filesystem. - /// - /// The name of the emoji must be at least 2 characters long and can only - /// contain alphanumeric characters and underscores. - /// - /// Requires the [Manage Emojis] permission. - /// - /// # Examples - /// - /// See the [`EditProfile::avatar`] example for an in-depth example as to - /// how to read an image from the filesystem and encode it as base64. Most - /// of the example can be applied similarly for this method. - /// - /// [`EditProfile::avatar`]: ../builder/struct.EditProfile.html#method.avatar - /// [`utils::read_image`]: ../fn.read_image.html - /// [Manage Emojis]: permissions/constant.MANAGE_EMOJIS.html - #[inline] - pub fn create_emoji(&self, name: &str, image: &str) -> FutureResult<Emoji> { - ftryopt!(self.client).http.create_emoji(self.id.0, name, image) - } - - /// Creates an integration for the guild. - /// - /// Requires the [Manage Guild] permission. - /// - /// [Manage Guild]: permissions/constant.MANAGE_GUILD.html - #[inline] - pub fn create_integration<I>(&self, integration_id: I, kind: &str) - -> FutureResult<()> where I: Into<IntegrationId> { - ftryopt!(self.client).http.create_guild_integration( - self.id.0, - integration_id.into().0, - kind, - ) - } - - /// Creates a new role in the guild with the data set, if any. - /// - /// **Note**: Requires the [Manage Roles] permission. - /// - /// # Examples - /// - /// Create a role which can be mentioned, with the name 'test': - /// - /// ```rust,ignore - /// // assuming a `guild` has been bound - /// - /// let role = guild.create_role(|r| r.hoist(true).name("role")); - /// ``` - /// - /// # Errors - /// - /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`] - /// if the current user does not have permission to perform bans. - /// - /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions - /// [`Role`]: struct.Role.html - /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html - pub fn create_role<F>(&self, f: F) -> FutureResult<Role> - where F: FnOnce(EditRole) -> EditRole { - #[cfg(feature = "cache")] - { - let req = Permissions::MANAGE_ROLES; - - if !self.has_perms(req) { - return Box::new(future::err(Error::Model( - ModelError::InvalidPermissions(req), - ))); - } - } - - ftryopt!(self.client).http.create_role(self.id.0, f) - } - - /// Deletes the current guild if the current user is the owner of the - /// guild. - /// - /// **Note**: Requires the current user to be the owner of the guild. - /// - /// # Errors - /// - /// If the `cache` is enabled, then returns a [`ModelError::InvalidUser`] - /// if the current user is not the guild owner. - /// - /// [`ModelError::InvalidUser`]: enum.ModelError.html#variant.InvalidUser - pub fn delete(&self) -> FutureResult<PartialGuild> { - let client = ftryopt!(self.client); - - #[cfg(feature = "cache")] - { - let cache = ftry!(client.cache.try_borrow()); - - if self.owner_id != cache.user.id { - let req = Permissions::MANAGE_GUILD; - - return Box::new(future::err(Error::Model( - ModelError::InvalidPermissions(req), - ))); - } - } - - ftryopt!(self.client).http.delete_guild(self.id.0) - } - - /// Deletes an [`Emoji`] from the guild. - /// - /// Requires the [Manage Emojis] permission. - /// - /// [`Emoji`]: struct.Emoji.html - /// [Manage Emojis]: permissions/constant.MANAGE_EMOJIS.html - #[inline] - pub fn delete_emoji<E: Into<EmojiId>>(&self, emoji_id: E) - -> FutureResult<()> { - ftryopt!(self.client).http.delete_emoji(self.id.0, emoji_id.into().0) - } - - /// Deletes an integration by Id from the guild. - /// - /// Requires the [Manage Guild] permission. - /// - /// [Manage Guild]: permissions/constant.MANAGE_GUILD.html - #[inline] - pub fn delete_integration<I: Into<IntegrationId>>(&self, integration_id: I) - -> FutureResult<()> { - ftryopt!(self.client).http.delete_guild_integration( - self.id.0, - integration_id.into().0, - ) - } - - /// Deletes a [`Role`] by Id from the guild. - /// - /// Also see [`Role::delete`] if you have the `cache` and `methods` features - /// enabled. - /// - /// Requires the [Manage Roles] permission. - /// - /// [`Role`]: struct.Role.html - /// [`Role::delete`]: struct.Role.html#method.delete - /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html - #[inline] - pub fn delete_role<R: Into<RoleId>>(&self, role_id: R) -> FutureResult<()> { - ftryopt!(self.client).http.delete_role(self.id.0, role_id.into().0) - } - - /// Edits the current guild with new data where specified. - /// - /// Refer to `EditGuild`'s documentation for a full list of methods. - /// - /// **Note**: Requires the current user to have the [Manage Guild] - /// permission. - /// - /// # Examples - /// - /// Change a guild's icon using a file name "icon.png": - /// - /// ```rust,ignore - /// use serenity::utils; - /// - /// // We are using read_image helper function from utils. - /// let base64_icon = utils::read_image("./icon.png") - /// .expect("Failed to read image"); - /// - /// guild.edit(|g| g.icon(base64_icon)); - /// ``` - /// - /// # Errors - /// - /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`] - /// if the current user does not have permission to perform bans. - /// - /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions - /// [Manage Guild]: permissions/constant.MANAGE_GUILD.html - pub fn edit<F: FnOnce(EditGuild) -> EditGuild>(&self, f: F) - -> FutureResult<PartialGuild> { - #[cfg(feature = "cache")] - { - let req = Permissions::MANAGE_GUILD; - - if !self.has_perms(req) { - return Box::new(future::err(Error::Model( - ModelError::InvalidPermissions(req), - ))); - } - } - - ftryopt!(self.client).http.edit_guild(self.id.0, f) - } - - /// Edits an [`Emoji`]'s name in the guild. - /// - /// Also see [`Emoji::edit`] if you have the `cache` and `methods` features - /// enabled. - /// - /// Requires the [Manage Emojis] permission. - /// - /// [`Emoji`]: struct.Emoji.html - /// [`Emoji::edit`]: struct.Emoji.html#method.edit - /// [Manage Emojis]: permissions/constant.MANAGE_EMOJIS.html - #[inline] - pub fn edit_emoji<E: Into<EmojiId>>(&self, emoji_id: E, name: &str) - -> FutureResult<Emoji> { - let emoji_id = emoji_id.into().0; - - ftryopt!(self.client).http.edit_emoji(self.id.0, emoji_id, name) - } - - /// Edits the properties of member of the guild, such as muting or - /// nicknaming them. - /// - /// Refer to `EditMember`'s documentation for a full list of methods and - /// permission restrictions. - /// - /// # Examples - /// - /// Mute a member and set their roles to just one role with a predefined Id: - /// - /// ```rust,ignore - /// guild.edit_member(user_id, |m| m.mute(true).roles(&vec![role_id])); - /// ``` - #[inline] - pub fn edit_member<F, U>(&self, user_id: U, f: F) -> FutureResult<()> - where F: FnOnce(EditMember) -> EditMember, U: Into<UserId> { - ftryopt!(self.client).http.edit_member(self.id.0, user_id.into().0, f) - } - - /// Edits the current user's nickname for the guild. - /// - /// Pass `None` to reset the nickname. - /// - /// **Note**: Requires the [Change Nickname] permission. - /// - /// # Errors - /// - /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`] - /// if the current user does not have permission to change their own - /// nickname. - /// - /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions - /// [Change Nickname]: permissions/constant.CHANGE_NICKNAME.html - pub fn edit_nickname(&self, new_nickname: Option<&str>) - -> FutureResult<()> { - #[cfg(feature = "cache")] - { - let req = Permissions::CHANGE_NICKNAME; - - if !self.has_perms(req) { - return Box::new(future::err(Error::Model( - ModelError::InvalidPermissions(req), - ))); - } - } - - ftryopt!(self.client).http.edit_nickname(self.id.0, new_nickname) - } - - /// Edits a role, optionally setting its fields. - /// - /// Requires the [Manage Roles] permission. - /// - /// # Examples - /// - /// Make a role hoisted: - /// - /// ```rust,ignore - /// guild.edit_role(RoleId(7), |r| r.hoist(true)); - /// ``` - /// - /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html - #[inline] - pub fn edit_role<F, R>(&self, role_id: R, f: F) -> FutureResult<Role> - where F: FnOnce(EditRole) -> EditRole, R: Into<RoleId> { - ftryopt!(self.client).http.edit_role(self.id.0, role_id.into().0, f) - } - - /// Edits the order of [`Role`]s - /// Requires the [Manage Roles] permission. - /// - /// # Examples - /// - /// Change the order of a role: - /// - /// ```rust,ignore - /// use serenity::model::RoleId; - /// guild.edit_role_position(RoleId(8), 2); - /// ``` - /// - /// [`Role`]: struct.Role.html - /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html - #[inline] - pub fn edit_role_position<R>(&self, role_id: R, position: u64) - -> FutureResult<Vec<Role>> where R: Into<RoleId> { - ftryopt!(self.client) - .http - .edit_role_position(self.id.0, role_id.into().0, position) - } - - /// Returns which of two [`User`]s has a higher [`Member`] hierarchy. - /// - /// Hierarchy is essentially who has the [`Role`] with the highest - /// [`position`]. - /// - /// Returns [`None`] if at least one of the given users' member instances - /// is not present. Returns `None` if the users have the same hierarchy, as - /// neither are greater than the other. - /// - /// If both user IDs are the same, `None` is returned. If one of the users - /// is the guild owner, their ID is returned. - #[cfg(feature = "cache")] - pub fn greater_member_hierarchy<T, U>(&self, lhs_id: T, rhs_id: U) - -> Option<UserId> where T: Into<UserId>, U: Into<UserId> { - let lhs_id = lhs_id.into(); - let rhs_id = rhs_id.into(); - - // Check that the IDs are the same. If they are, neither is greater. - if lhs_id == rhs_id { - return None; - } - - // Check if either user is the guild owner. - if lhs_id == self.owner_id { - return Some(lhs_id); - } else if rhs_id == self.owner_id { - return Some(rhs_id); - } - - let lhs = self.members.get(&lhs_id)? - .borrow() - .highest_role_info() - .unwrap_or((RoleId(0), 0)); - let rhs = self.members.get(&rhs_id)? - .borrow() - .highest_role_info() - .unwrap_or((RoleId(0), 0)); - - // If LHS and RHS both have no top position or have the same role ID, - // then no one wins. - if (lhs.1 == 0 && rhs.1 == 0) || (lhs.0 == rhs.0) { - return None; - } - - // If LHS's top position is higher than RHS, then LHS wins. - if lhs.1 > rhs.1 { - return Some(lhs_id) - } - - // If RHS's top position is higher than LHS, then RHS wins. - if rhs.1 > lhs.1 { - return Some(rhs_id); - } - - // If LHS and RHS both have the same position, but LHS has the lower - // role ID, then LHS wins. - // - // If RHS has the higher role ID, then RHS wins. - if lhs.1 == rhs.1 && lhs.0 < rhs.0 { - Some(lhs_id) - } else { - Some(rhs_id) - } - } - /// Returns the formatted URL of the guild's icon, if one exists. pub fn icon_url(&self) -> Option<String> { self.icon @@ -766,40 +174,6 @@ impl Guild { .map(|icon| format!(cdn!("/icons/{}/{}.webp"), self.id, icon)) } - /// Gets all integration of the guild. - /// - /// This performs a request over the REST API. - #[inline] - pub fn integrations(&self) -> FutureResult<Vec<Integration>> { - ftryopt!(self.client).http.get_guild_integrations(self.id.0) - } - - /// Retrieves the active invites for the guild. - /// - /// **Note**: Requires the [Manage Guild] permission. - /// - /// # Errors - /// - /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`] - /// if the current user does not have permission to perform bans. - /// - /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions - /// [Manage Guild]: permissions/constant.MANAGE_GUILD.html - pub fn invites(&self) -> FutureResult<Vec<RichInvite>> { - #[cfg(feature = "cache")] - { - let req = Permissions::MANAGE_GUILD; - - if !self.has_perms(req) { - return Box::new(future::err(Error::Model( - ModelError::InvalidPermissions(req), - ))); - } - } - - ftryopt!(self.client).http.get_guild_invites(self.id.0) - } - /// Checks if the guild is 'large'. A guild is considered large if it has /// more than 250 members. #[inline] @@ -807,47 +181,6 @@ impl Guild { self.members.len() > LARGE_THRESHOLD as usize } - /// Kicks a [`Member`] from the guild. - /// - /// Requires the [Kick Members] permission. - /// - /// [`Member`]: struct.Member.html - /// [Kick Members]: permissions/constant.KICK_MEMBERS.html - #[inline] - pub fn kick<U: Into<UserId>>(&self, user_id: U) -> FutureResult<()> { - ftryopt!(self.client).http.kick_member(self.id.0, user_id.into().0) - } - - /// Leaves the guild. - #[inline] - pub fn leave(&self) -> FutureResult<()> { - ftryopt!(self.client).http.leave_guild(self.id.0) - } - - /// Gets a user's [`Member`] for the guild by Id. - /// - /// [`Guild`]: struct.Guild.html - /// [`Member`]: struct.Member.html - #[inline] - pub fn member<U: Into<UserId>>(&self, user_id: U) -> FutureResult<Member> { - ftryopt!(self.client).http.get_member(self.id.0, user_id.into().0) - } - - /// Gets a list of the guild's members. - /// - /// Optionally pass in the `limit` to limit the number of results. Maximum - /// value is 1000. Optionally pass in `after` to offset the results by a - /// [`User`]'s Id. - /// - /// [`User`]: struct.User.html - #[inline] - pub fn members<U>(&self, limit: Option<u64>, after: Option<U>) - -> FutureResult<Vec<Member>> where U: Into<UserId> { - let after = after.map(Into::into).map(|x| x.0); - - ftryopt!(self.client).http.get_guild_members(self.id.0, limit, after) - } - /// Gets a list of all the members (satisfying the status provided to the function) in this /// guild. pub fn members_with_status(&self, status: OnlineStatus) @@ -1251,21 +584,6 @@ impl Guild { permissions } - /// Moves a member to a specific voice channel. - /// - /// Requires the [Move Members] permission. - /// - /// [Move Members]: permissions/constant.MOVE_MEMBERS.html - #[inline] - pub fn move_member<C, U>(&self, user_id: U, channel_id: C) - -> FutureResult<()> where C: Into<ChannelId>, U: Into<UserId> { - ftryopt!(self.client).http.edit_member( - self.id.0, - user_id.into().0, - |f| f.voice_channel(channel_id.into().0), - ) - } - /// Alias for [`permissions_in`]. /// /// [`permissions_in`]: #method.permissions_in @@ -1417,50 +735,6 @@ impl Guild { permissions } - /// Retrieves the count of the number of [`Member`]s that would be pruned - /// with the number of given days. - /// - /// See the documentation on [`GuildPrune`] for more information. - /// - /// **Note**: Requires the [Kick Members] permission. - /// - /// # Errors - /// - /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`] - /// if the current user does not have permission to perform bans. - /// - /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions - /// [`GuildPrune`]: struct.GuildPrune.html - /// [`Member`]: struct.Member.html - /// [Kick Members]: permissions/constant.KICK_MEMBERS.html - pub fn prune_count(&self, days: u16) -> FutureResult<GuildPrune> { - #[cfg(feature = "cache")] - { - let req = Permissions::KICK_MEMBERS; - - if !self.has_perms(req) { - return Box::new(future::err(Error::Model( - ModelError::InvalidPermissions(req), - ))); - } - } - - ftryopt!(self.client).http.get_guild_prune_count(self.id.0, days) - } - - /// Re-orders the channels of the guild. - /// - /// Although not required, you should specify all channels' positions, - /// regardless of whether they were updated. Otherwise, positioning can - /// sometimes get weird. - pub fn reorder_channels<It>(&self, channels: It) -> FutureResult<()> - where It: IntoIterator<Item = (ChannelId, u64)> { - ftryopt!(self.client).http.edit_guild_channel_positions( - self.id.0, - channels, - ) - } - /// Returns the Id of the shard associated with the guild. /// /// When the cache is enabled this will automatically retrieve the total @@ -1492,87 +766,6 @@ impl Guild { .map(|icon| format!(cdn!("/splashes/{}/{}.webp"), self.id, icon)) } - /// Starts an integration sync for the given integration Id. - /// - /// Requires the [Manage Guild] permission. - /// - /// [Manage Guild]: permissions/constant.MANAGE_GUILD.html - #[inline] - pub fn start_integration_sync<I>(&self, integration_id: I) - -> FutureResult<()> where I: Into<IntegrationId> { - ftryopt!(self.client).http.start_integration_sync( - self.id.0, - integration_id.into().0, - ) - } - - /// Starts a prune of [`Member`]s. - /// - /// See the documentation on [`GuildPrune`] for more information. - /// - /// **Note**: Requires the [Kick Members] permission. - /// - /// # Errors - /// - /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`] - /// if the current user does not have permission to perform bans. - /// - /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions - /// [`GuildPrune`]: struct.GuildPrune.html - /// [`Member`]: struct.Member.html - /// [Kick Members]: permissions/constant.KICK_MEMBERS.html - pub fn start_prune(&self, days: u16) -> FutureResult<GuildPrune> { - #[cfg(feature = "cache")] - { - let req = Permissions::KICK_MEMBERS; - - if !self.has_perms(req) { - return Box::new(future::err(Error::Model( - ModelError::InvalidPermissions(req), - ))); - } - } - - ftryopt!(self.client).http.start_guild_prune(self.id.0, days) - } - - /// Unbans the given [`User`] from the guild. - /// - /// **Note**: Requires the [Ban Members] permission. - /// - /// # Errors - /// - /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`] - /// if the current user does not have permission to perform bans. - /// - /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions - /// [`User`]: struct.User.html - /// [Ban Members]: permissions/constant.BAN_MEMBERS.html - pub fn unban<U: Into<UserId>>(&self, user_id: U) -> FutureResult<()> { - #[cfg(feature = "cache")] - { - let req = Permissions::BAN_MEMBERS; - - if !self.has_perms(req) { - return Box::new(future::err(Error::Model( - ModelError::InvalidPermissions(req), - ))); - } - } - - ftryopt!(self.client).http.remove_ban(self.id.0, user_id.into().0) - } - - /// Retrieves the guild's webhooks. - /// - /// **Note**: Requires the [Manage Webhooks] permission. - /// - /// [Manage Webhooks]: permissions/constant.MANAGE_WEBHOOKS.html - #[inline] - pub fn webhooks(&self) -> FutureResult<Vec<Webhook>> { - ftryopt!(self.client).http.get_guild_webhooks(self.id.0) - } - /// Obtain a reference to a role by its name. /// /// **Note**: If two or more roles have the same name, obtained reference will be one of @@ -1752,7 +945,6 @@ impl<'de> Deserialize<'de> for Guild { application_id: application_id, afk_timeout: afk_timeout, channels: channels, - client: None, default_message_notifications: default_message_notifications, emojis: emojis, explicit_content_filter: explicit_content_filter, @@ -1778,13 +970,11 @@ impl<'de> Deserialize<'de> for Guild { } /// Checks if a `&str` contains another `&str`. -#[cfg(feature = "model")] fn contains_case_insensitive(to_look_at: &str, to_find: &str) -> bool { to_look_at.to_lowercase().contains(to_find) } /// Checks if a `&str` starts with another `&str`. -#[cfg(feature = "model")] fn starts_with_case_insensitive(to_look_at: &str, to_find: &str) -> bool { to_look_at.to_lowercase().starts_with(to_find) } @@ -1796,7 +986,6 @@ fn starts_with_case_insensitive(to_look_at: &str, to_find: &str) -> bool { /// expected to contain `origin` as substring. /// If not, using `closest_to_origin` would sort these /// the end. -#[cfg(feature = "model")] fn closest_to_origin(origin: &str, word_a: &str, word_b: &str) -> std::cmp::Ordering { let value_a = match word_a.find(origin) { Some(value) => value + word_a.len(), @@ -1882,7 +1071,6 @@ impl From<u64> for GuildContainer { fn from(id: u64) -> GuildContainer { GuildContainer::Id(GuildId(id)) } } -#[cfg(feature = "model")] impl InviteGuild { /// Returns the formatted URL of the guild's splash image, if one exists. pub fn splash_url(&self) -> Option<String> { @@ -1914,7 +1102,6 @@ pub enum GuildStatus { Offline(GuildUnavailable), } -#[cfg(feature = "model")] impl GuildStatus { /// Retrieves the Id of the inner [`Guild`]. /// diff --git a/src/model/guild/partial_guild.rs b/src/model/guild/partial_guild.rs index 6b0b3d2..39f158a 100644 --- a/src/model/guild/partial_guild.rs +++ b/src/model/guild/partial_guild.rs @@ -1,13 +1,8 @@ -use futures::{Future, future}; use model::prelude::*; use std::cell::RefCell; use std::rc::Rc; use super::super::utils::{deserialize_emojis, deserialize_roles}; -use super::super::WrappedClient; -use ::FutureResult; -#[cfg(feature = "model")] -use builder::{EditGuild, EditMember, EditRole}; /// Partial information about a [`Guild`]. This does not include information /// like member data. @@ -38,304 +33,9 @@ pub struct PartialGuild { pub roles: HashMap<RoleId, Rc<RefCell<Role>>>, pub splash: Option<String>, pub verification_level: VerificationLevel, - #[serde(skip)] - pub(crate) client: WrappedClient, } -#[cfg(feature = "model")] impl PartialGuild { - /// Ban a [`User`] from the guild. All messages by the - /// user within the last given number of days given will be deleted. This - /// may be a range between `0` and `7`. - /// - /// **Note**: Requires the [Ban Members] permission. - /// - /// # Examples - /// - /// Ban a member and remove all messages they've sent in the last 4 days: - /// - /// ```rust,ignore - /// // assumes a `user` and `guild` have already been bound - /// let _ = guild.ban(user, 4); - /// ``` - /// - /// # Errors - /// - /// Returns a [`ModelError::DeleteMessageDaysAmount`] if the number of - /// days' worth of messages to delete is over the maximum. - /// - /// [`ModelError::DeleteMessageDaysAmount`]: - /// enum.ModelError.html#variant.DeleteMessageDaysAmount - /// [`User`]: struct.User.html - /// [Ban Members]: permissions/constant.BAN_MEMBERS.html - // todo: add ban reason - pub fn ban<U: Into<UserId>>(&self, user_id: U, delete_message_days: u8) - -> FutureResult<()> { - if delete_message_days > 7 { - return Box::new(future::err(Error::Model( - ModelError::DeleteMessageDaysAmount(delete_message_days), - ))); - } - - Box::new(ftryopt!(self.client).http.ban_user( - self.id.0, - user_id.into().0, - delete_message_days, - "", - )) - } - - /// Gets a list of the guild's bans. - /// - /// Requires the [Ban Members] permission. - /// - /// [Ban Members]: permissions/constant.BAN_MEMBERS.html - #[inline] - pub fn bans(&self) -> FutureResult<Vec<Ban>> { - ftryopt!(self.client).http.get_bans(self.id.0) - } - - /// Gets all of the guild's channels over the REST API. - /// - /// [`Guild`]: struct.Guild.html - #[inline] - pub fn channels(&self) -> FutureResult<HashMap<ChannelId, GuildChannel>> { - let done = ftryopt!(self.client) - .http - .get_channels(self.id.0) - .map(|channels| { - let mut map = HashMap::with_capacity(channels.len()); - - for channel in channels { - map.insert(channel.id, channel); - } - - map - }); - - Box::new(done) - } - - /// Creates a [`GuildChannel`] in the guild. - /// - /// Refer to [`http::create_channel`] for more information. - /// - /// Requires the [Manage Channels] permission. - /// - /// # Examples - /// - /// Create a voice channel in a guild with the name `test`: - /// - /// ```rust,ignore - /// use serenity::model::ChannelType; - /// - /// guild.create_channel("test", ChannelType::Voice, None); - /// ``` - /// - /// [`GuildChannel`]: struct.GuildChannel.html - /// [`http::create_channel`]: ../http/fn.create_channel.html - /// [Manage Channels]: permissions/constant.MANAGE_CHANNELS.html - #[inline] - pub fn create_channel<C>(&self, name: &str, kind: ChannelType, category: C) - -> FutureResult<GuildChannel> where C: Into<Option<ChannelId>> { - ftryopt!(self.client).http.create_channel( - self.id.0, - name, - kind, - category.into().map(|x| x.0), - ) - } - - /// Creates an emoji in the guild with a name and base64-encoded image. - /// - /// Refer to the documentation for [`Guild::create_emoji`] for more - /// information. - /// - /// Requires the [Manage Emojis] permission. - /// - /// # Examples - /// - /// See the [`EditProfile::avatar`] example for an in-depth example as to - /// how to read an image from the filesystem and encode it as base64. Most - /// of the example can be applied similarly for this method. - /// - /// [`EditProfile::avatar`]: ../builder/struct.EditProfile.html#method.avatar - /// [`Guild::create_emoji`]: struct.Guild.html#method.create_emoji - /// [`utils::read_image`]: ../utils/fn.read_image.html - /// [Manage Emojis]: permissions/constant.MANAGE_EMOJIS.html - #[inline] - pub fn create_emoji(&self, name: &str, image: &str) -> FutureResult<Emoji> { - ftryopt!(self.client).http.create_emoji(self.id.0, name, image) - } - - /// Creates an integration for the guild. - /// - /// Requires the [Manage Guild] permission. - /// - /// [Manage Guild]: permissions/constant.MANAGE_GUILD.html - #[inline] - pub fn create_integration<I>(&self, integration_id: I, kind: &str) - -> FutureResult<()> where I: Into<IntegrationId> { - ftryopt!(self.client).http.create_guild_integration( - self.id.0, - integration_id.into().0, - kind, - ) - } - - /// Creates a new role in the guild with the data set, if any. - /// - /// See the documentation for [`Guild::create_role`] on how to use this. - /// - /// **Note**: Requires the [Manage Roles] permission. - /// - /// # Errors - /// - /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`] - /// if the current user does not have permission to perform bans. - /// - /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions - /// [`Guild::create_role`]: struct.Guild.html#method.create_role - /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html - #[inline] - pub fn create_role<F: FnOnce(EditRole) -> EditRole>(&self, f: F) - -> FutureResult<Role> { - ftryopt!(self.client).http.create_role(self.id.0, f) - } - - /// Deletes the current guild if the current user is the owner of the - /// guild. - /// - /// **Note**: Requires the current user to be the owner of the guild. - #[inline] - pub fn delete(&self) -> FutureResult<PartialGuild> { - ftryopt!(self.client).http.delete_guild(self.id.0) - } - - /// Deletes an [`Emoji`] from the guild. - /// - /// Requires the [Manage Emojis] permission. - /// - /// [`Emoji`]: struct.Emoji.html - /// [Manage Emojis]: permissions/constant.MANAGE_EMOJIS.html - #[inline] - pub fn delete_emoji<E: Into<EmojiId>>(&self, emoji_id: E) - -> FutureResult<()> { - ftryopt!(self.client).http.delete_emoji(self.id.0, emoji_id.into().0) - } - - /// Deletes an integration by Id from the guild. - /// - /// Requires the [Manage Guild] permission. - /// - /// [Manage Guild]: permissions/constant.MANAGE_GUILD.html - #[inline] - pub fn delete_integration<I: Into<IntegrationId>>(&self, integration_id: I) - -> FutureResult<()> { - ftryopt!(self.client).http.delete_guild_integration( - self.id.0, - integration_id.into().0, - ) - } - - /// Deletes a [`Role`] by Id from the guild. - /// - /// Also see [`Role::delete`] if you have the `cache` and `methods` features - /// enabled. - /// - /// Requires the [Manage Roles] permission. - /// - /// [`Role`]: struct.Role.html - /// [`Role::delete`]: struct.Role.html#method.delete - /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html - #[inline] - pub fn delete_role<R: Into<RoleId>>(&self, role_id: R) -> FutureResult<()> { - let role_id = role_id.into().0; - - ftryopt!(self.client).http.delete_role(self.id.0, role_id) - } - - /// Edits the current guild with new data where specified. - /// - /// **Note**: Requires the current user to have the [Manage Guild] - /// permission. - /// - /// [Manage Guild]: permissions/constant.MANAGE_GUILD.html - pub fn edit<'a, F: FnOnce(EditGuild) -> EditGuild>(&self, f: F) - -> FutureResult<PartialGuild> { - ftryopt!(self.client).http.edit_guild(self.id.0, f) - } - - /// Edits an [`Emoji`]'s name in the guild. - /// - /// Also see [`Emoji::edit`] if you have the `cache` and `methods` features - /// enabled. - /// - /// Requires the [Manage Emojis] permission. - /// - /// [`Emoji`]: struct.Emoji.html - /// [`Emoji::edit`]: struct.Emoji.html#method.edit - /// [Manage Emojis]: permissions/constant.MANAGE_EMOJIS.html - #[inline] - pub fn edit_emoji<E: Into<EmojiId>>(&self, emoji_id: E, name: &str) - -> FutureResult<Emoji> { - ftryopt!(self.client) - .http - .edit_emoji(self.id.0, emoji_id.into().0, name) - } - - /// Edits the properties of member of the guild, such as muting or - /// nicknaming them. - /// - /// Refer to `EditMember`'s documentation for a full list of methods and - /// permission restrictions. - /// - /// # Examples - /// - /// Mute a member and set their roles to just one role with a predefined Id: - /// - /// ```rust,ignore - /// use serenity::model::GuildId; - /// - /// GuildId(7).edit_member(user_id, |m| m.mute(true).roles(&vec![role_id])); - /// ``` - #[inline] - pub fn edit_member<F, U>(&self, user_id: U, f: F) -> FutureResult<()> - where F: FnOnce(EditMember) -> EditMember, U: Into<UserId> { - ftryopt!(self.client).http.edit_member(self.id.0, user_id.into().0, f) - } - - /// Edits the current user's nickname for the guild. - /// - /// Pass `None` to reset the nickname. - /// - /// **Note**: Requires the [Change Nickname] permission. - /// - /// # Errors - /// - /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`] - /// if the current user does not have permission to change their own - /// nickname. - /// - /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions - /// [Change Nickname]: permissions/constant.CHANGE_NICKNAME.html - #[inline] - pub fn edit_nickname(&self, new_nickname: Option<&str>) - -> FutureResult<()> { - ftryopt!(self.client).http.edit_nickname(self.id.0, new_nickname) - } - - /// Kicks a [`Member`] from the guild. - /// - /// Requires the [Kick Members] permission. - /// - /// [`Member`]: struct.Member.html - /// [Kick Members]: permissions/constant.KICK_MEMBERS.html - #[inline] - pub fn kick<U: Into<UserId>>(&self, user_id: U) -> FutureResult<()> { - ftryopt!(self.client).http.kick_member(self.id.0, user_id.into().0) - } - /// Returns a formatted URL of the guild's icon, if the guild has an icon. pub fn icon_url(&self) -> Option<String> { self.icon @@ -343,78 +43,6 @@ impl PartialGuild { .map(|icon| format!(cdn!("/icons/{}/{}.webp"), self.id, icon)) } - /// Gets all integration of the guild. - /// - /// This performs a request over the REST API. - #[inline] - pub fn integrations(&self) -> FutureResult<Vec<Integration>> { - ftryopt!(self.client).http.get_guild_integrations(self.id.0) - } - - /// Gets all of the guild's invites. - /// - /// Requires the [Manage Guild] permission. - /// - /// [Manage Guild]: permissions/constant.MANAGE_GUILD.html - #[inline] - pub fn invites(&self) -> FutureResult<Vec<RichInvite>> { - ftryopt!(self.client).http.get_guild_invites(self.id.0) - } - - /// Leaves the guild. - #[inline] - pub fn leave(&self) -> FutureResult<()> { - ftryopt!(self.client).http.leave_guild(self.id.0) - } - - /// Gets a user's [`Member`] for the guild by Id. - /// - /// [`Guild`]: struct.Guild.html - /// [`Member`]: struct.Member.html - pub fn member<U: Into<UserId>>(&self, user_id: U) -> FutureResult<Member> { - ftryopt!(self.client).http.get_member(self.id.0, user_id.into().0) - } - - /// Gets a list of the guild's members. - /// - /// Optionally pass in the `limit` to limit the number of results. Maximum - /// value is 1000. Optionally pass in `after` to offset the results by a - /// [`User`]'s Id. - /// - /// [`User`]: struct.User.html - pub fn members<U: Into<UserId>>(&self, limit: Option<u64>, after: Option<U>) - -> FutureResult<Vec<Member>> { - let after = after.map(Into::into).map(|x| x.0); - - ftryopt!(self.client).http.get_guild_members(self.id.0, limit, after) - } - - /// Moves a member to a specific voice channel. - /// - /// Requires the [Move Members] permission. - /// - /// [Move Members]: permissions/constant.MOVE_MEMBERS.html - #[inline] - pub fn move_member<C, U>(&self, user_id: U, channel_id: C) - -> FutureResult<()> where C: Into<ChannelId>, U: Into<UserId> { - ftryopt!(self.client) - .http - .edit_member(self.id.0, user_id.into().0, |f| f - .voice_channel(channel_id.into().0)) - } - - /// Gets the number of [`Member`]s that would be pruned with the given - /// number of days. - /// - /// Requires the [Kick Members] permission. - /// - /// [`Member`]: struct.Member.html - /// [Kick Members]: permissions/constant.KICK_MEMBERS.html - #[inline] - pub fn prune_count(&self, days: u16) -> FutureResult<GuildPrune> { - ftryopt!(self.client).http.get_guild_prune_count(self.id.0, days) - } - /// Returns the Id of the shard associated with the guild. /// /// When the cache is enabled this will automatically retrieve the total @@ -446,40 +74,6 @@ impl PartialGuild { .map(|icon| format!(cdn!("/splashes/{}/{}.webp"), self.id, icon)) } - /// Starts an integration sync for the given integration Id. - /// - /// Requires the [Manage Guild] permission. - /// - /// [Manage Guild]: permissions/constant.MANAGE_GUILD.html - #[inline] - pub fn start_integration_sync<I>(&self, integration_id: I) - -> FutureResult<()> where I: Into<IntegrationId> { - ftryopt!(self.client) - .http - .start_integration_sync(self.id.0, integration_id.into().0) - } - - /// Unbans a [`User`] from the guild. - /// - /// Requires the [Ban Members] permission. - /// - /// [`User`]: struct.User.html - /// [Ban Members]: permissions/constant.BAN_MEMBERS.html - #[inline] - pub fn unban<U: Into<UserId>>(&self, user_id: U) -> FutureResult<()> { - ftryopt!(self.client).http.remove_ban(self.id.0, user_id.into().0) - } - - /// Retrieves the guild's webhooks. - /// - /// **Note**: Requires the [Manage Webhooks] permission. - /// - /// [Manage Webhooks]: permissions/constant.MANAGE_WEBHOOKS.html - #[inline] - pub fn webhooks(&self) -> FutureResult<Vec<Webhook>> { - ftryopt!(self.client).http.get_guild_webhooks(self.id.0) - } - /// Obtain a reference to a role by its name. /// /// **Note**: If two or more roles have the same name, obtained reference will be one of diff --git a/src/model/guild/role.rs b/src/model/guild/role.rs index bcb142a..bdc6e77 100644 --- a/src/model/guild/role.rs +++ b/src/model/guild/role.rs @@ -1,12 +1,5 @@ use model::prelude::*; use std::cmp::Ordering; -use super::super::WrappedClient; -use ::FutureResult; - -#[cfg(all(feature = "builder", feature = "cache", feature = "model"))] -use builder::EditRole; -#[cfg(all(feature = "cache", feature = "model"))] -use internal::prelude::*; /// Information about a role within a guild. A role represents a set of /// permissions, and can be attached to one or multiple users. A role has @@ -57,76 +50,9 @@ pub struct Role { /// /// The `@everyone` role is usually either `-1` or `0`. pub position: i64, - #[serde(skip)] - pub(crate) client: WrappedClient, } -#[cfg(feature = "model")] impl Role { - /// Deletes the role. - /// - /// **Note** Requires the [Manage Roles] permission. - /// - /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html - #[cfg(feature = "cache")] - #[inline] - pub fn delete(&self) -> FutureResult<()> { - let guild_id = ftry!(self.find_guild()); - - ftryopt!(self.client).http.delete_role(guild_id.0, self.id.0) - } - - /// Edits a [`Role`], optionally setting its new fields. - /// - /// Requires the [Manage Roles] permission. - /// - /// # Examples - /// - /// Make a role hoisted: - /// - /// ```rust,no_run - /// # use serenity::model::id::RoleId; - /// # let role = RoleId(7).find().unwrap(); - /// // assuming a `role` has already been bound - // - /// role.edit(|r| r.hoist(true)); - /// ``` - /// - /// [`Role`]: struct.Role.html - /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html - #[cfg(all(feature = "builder", feature = "cache"))] - pub fn edit<F: FnOnce(EditRole) -> EditRole>(&self, f: F) - -> FutureResult<Role> { - let guild_id = ftry!(self.find_guild()); - - ftryopt!(self.client).http.edit_role(guild_id.0, self.id.0, f) - } - - /// Searches the cache for the guild that owns the role. - /// - /// # Errors - /// - /// Returns a [`ModelError::GuildNotFound`] if a guild is not in the cache - /// that contains the role. - /// - /// [`ModelError::GuildNotFound`]: enum.ModelError.html#variant.GuildNotFound - #[cfg(feature = "cache")] - pub fn find_guild(&self) -> Result<GuildId> { - let client = self.client.as_ref().ok_or_else(|| { - Error::Model(ModelError::ClientNotPresent) - })?; - - for guild in client.cache.borrow().guilds.values() { - let guild = guild.borrow(); - - if guild.roles.contains_key(&RoleId(self.id.0)) { - return Ok(guild.id); - } - } - - Err(Error::Model(ModelError::GuildNotFound)) - } - /// Check that the role has the given permission. #[inline] pub fn has_permission(&self, permission: Permissions) -> bool { |