diff --git a/definitions/structs/member.yml b/definitions/structs/member.yml index ebe8fa0e323..585d780040e 100644 --- a/definitions/structs/member.yml +++ b/definitions/structs/member.yml @@ -5,6 +5,10 @@ fields: - name: deaf description: True if user isn't allowed to hear in voice channels. type: bool + - name: guild_id + description: The Id of the guild that the member is a part of. + optional: true + type: GuildId - name: joined_at description: Timestamp representing the date when the member joined. type: string diff --git a/src/client/rest/mod.rs b/src/client/rest/mod.rs index 6b5b055ac82..a9dc88c482e 100644 --- a/src/client/rest/mod.rs +++ b/src/client/rest/mod.rs @@ -48,7 +48,7 @@ use std::sync::{Arc, Mutex}; use ::constants::{self, ErrorCode}; use ::internal::prelude::*; use ::model::*; -use ::utils::decode_array; +use ::utils::{decode_array, into_array}; /// An method used for ratelimiting special routes. /// @@ -1048,7 +1048,10 @@ pub fn get_guild_members(guild_id: u64, limit: Option, after: Option) limit.unwrap_or(500), after.unwrap_or(0)); - decode_array(serde_json::from_reader(response)?, Member::decode) + into_array(serde_json::from_reader(response)?) + .and_then(|x| x.into_iter() + .map(|v| Member::decode_guild(GuildId(guild_id), v)) + .collect()) } /// Gets the amount of users that can be pruned. @@ -1167,7 +1170,7 @@ pub fn get_member(guild_id: u64, user_id: u64) -> Result { guild_id, user_id); - Member::decode(serde_json::from_reader(response)?) + Member::decode_guild(GuildId(guild_id), serde_json::from_reader(response)?) } /// Gets a message by an Id, bots only. diff --git a/src/ext/cache/mod.rs b/src/ext/cache/mod.rs index 7d00b2a2638..ad0ef31a47b 100644 --- a/src/ext/cache/mod.rs +++ b/src/ext/cache/mod.rs @@ -804,6 +804,7 @@ impl Cache { if !found { guild.members.insert(event.user.id, Member { deaf: false, + guild_id: Some(event.guild_id), joined_at: String::default(), mute: false, nick: event.nick.clone(), diff --git a/src/model/event.rs b/src/model/event.rs index b9801dc78cf..5ae66295eb1 100644 --- a/src/model/event.rs +++ b/src/model/event.rs @@ -312,9 +312,11 @@ impl GuildMemberAddEvent { #[doc(hidden)] #[inline] pub fn decode(mut map: Map) -> Result { + let guild_id = remove(&mut map, "guild_id").and_then(GuildId::decode)?; + Ok(GuildMemberAddEvent { - guild_id: remove(&mut map, "guild_id").and_then(GuildId::decode)?, - member: Member::decode(Value::Object(map))?, + guild_id: guild_id, + member: Member::decode_guild(guild_id, Value::Object(map))?, }) } } @@ -367,9 +369,11 @@ impl GuildMembersChunkEvent { #[doc(hidden)] #[inline] pub fn decode(mut map: Map) -> Result { + let guild_id = remove(&mut map, "guild_id").and_then(GuildId::decode)?; + Ok(GuildMembersChunkEvent { - guild_id: remove(&mut map, "guild_id").and_then(GuildId::decode)?, - members: remove(&mut map, "members").and_then(decode_members)?, + guild_id: guild_id, + members: remove(&mut map, "members").and_then(|x| decode_guild_members(guild_id, x))?, }) } } diff --git a/src/model/guild.rs b/src/model/guild.rs index 8fa6d0eac3b..b3879b1017b 100644 --- a/src/model/guild.rs +++ b/src/model/guild.rs @@ -1734,6 +1734,15 @@ impl Member { roles.iter().find(|r| r.colour.0 != default.0).map(|r| r.colour) } + #[doc(hidden)] + pub fn decode_guild(guild_id: GuildId, mut value: Value) -> Result { + if let Some(v) = value.as_object_mut() { + v.insert("guild_id".to_owned(), Value::U64(guild_id.0)); + } + + Self::decode(value) + } + /// Calculates the member's display name. /// /// The nickname takes priority over the member's username if it exists. @@ -1768,6 +1777,8 @@ impl Member { /// Finds the Id of the [`Guild`] that the member is in. /// + /// If some value is present in [`guild_id`], then that value is returned. + /// /// # Errors /// /// Returns a [`ClientError::GuildNotFound`] if the guild could not be @@ -1775,8 +1786,13 @@ impl Member { /// /// [`ClientError::GuildNotFound`]: ../client/enum.ClientError.html#variant.GuildNotFound /// [`Guild`]: struct.Guild.html + /// [`guild_id`]: #structfield.guild_id #[cfg(feature="cache")] pub fn find_guild(&self) -> Result { + if let Some(guild_id) = self.guild_id { + return Ok(guild_id); + } + for guild in CACHE.read().unwrap().guilds.values() { let guild = guild.read().unwrap(); diff --git a/src/model/utils.rs b/src/model/utils.rs index 8de7dd2d28f..17f91f12932 100644 --- a/src/model/utils.rs +++ b/src/model/utils.rs @@ -1,21 +1,6 @@ use std::collections::{BTreeMap, HashMap}; use std::sync::{Arc, RwLock}; -use super::{ - Channel, - ChannelId, - Emoji, - EmojiId, - Member, - Message, - Presence, - ReadState, - Relationship, - Role, - RoleId, - User, - UserId, - VoiceState, -}; +use super::*; use ::internal::prelude::*; use ::utils::{decode_array, into_array}; @@ -100,6 +85,23 @@ pub fn decode_members(value: Value) -> Result> { Ok(members) } +pub fn decode_guild_members(guild_id: GuildId, value: Value) -> Result> { + let mut members = HashMap::new(); + let member_vec = into_array(value).map(|x| x + .into_iter() + .map(|v| Member::decode_guild(guild_id, v)) + .filter_map(Result::ok) + .collect::>())?; + + for member in member_vec { + let user_id = member.user.read().unwrap().id; + + members.insert(user_id, member); + } + + Ok(members) +} + // Clippy's lint is incorrect here and will result in invalid code. // // Bit more detaul: `result_unwrap_or_default` is not yet stable as of rustc diff --git a/tests/README.md b/tests/README.md new file mode 100644 index 00000000000..f67f67d2d09 --- /dev/null +++ b/tests/README.md @@ -0,0 +1,21 @@ +### Running the Ignored Test Suite + +Some tests are ignored by default, as they require authentication. These should +only be run when you need to actually test something that _requires_ hitting +Discord's REST API. + +### Generic Tests + +Provide the token by setting the environment variable `DISCORD_TOKEN`. + +e.g.: + +```sh +$ DISCORD_TOKEN=aaaaaaaaaaa TEST_USER=285951325479632862 cargo test -- --ignored +``` + +### Notes for Specific Tests + +issues/69: + +Provide a `TEST_USER` diff --git a/tests/issues/69.rs b/tests/issues/69.rs new file mode 100644 index 00000000000..342f7fc025e --- /dev/null +++ b/tests/issues/69.rs @@ -0,0 +1,16 @@ +extern crate serenity; + +use serenity::ext::cache::Cache; +use serenity::model::event::ChannelCreateEvent; +use serenity::model::GuildId; + +#[ignore] +fn test_private_channel_create() { + let cache = Cache::default(); + + let event = ChannelCreateEvent { + channel: Channel { + + } + } +}