twilight_model/guild/
member.rs

1//! Mostly internal custom serde deserializers.
2
3use super::MemberFlags;
4use crate::{
5    id::{marker::RoleMarker, Id},
6    user::User,
7    util::{ImageHash, Timestamp},
8};
9
10use serde::{Deserialize, Serialize};
11
12/// [`User`] that is in a [`Guild`].
13///
14/// [`Guild`]: super::Guild
15#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
16pub struct Member {
17    /// Member's guild avatar.
18    #[serde(skip_serializing_if = "Option::is_none")]
19    pub avatar: Option<ImageHash>,
20    pub communication_disabled_until: Option<Timestamp>,
21    pub deaf: bool,
22    /// Flags for the member.
23    ///
24    /// Defaults to an empty bitfield.
25    pub flags: MemberFlags,
26    pub joined_at: Option<Timestamp>,
27    pub mute: bool,
28    pub nick: Option<String>,
29    /// Whether the user has yet to pass the guild's [Membership Screening]
30    /// requirements.
31    #[serde(default)]
32    pub pending: bool,
33    #[serde(skip_serializing_if = "Option::is_none")]
34    pub premium_since: Option<Timestamp>,
35    pub roles: Vec<Id<RoleMarker>>,
36    pub user: User,
37}
38
39#[cfg(test)]
40mod tests {
41    use super::Member;
42    use crate::{
43        guild::MemberFlags,
44        id::Id,
45        test::image_hash,
46        user::User,
47        util::datetime::{Timestamp, TimestampParseError},
48    };
49    use serde_test::Token;
50    use std::str::FromStr;
51
52    #[test]
53    fn member_deserializer() -> Result<(), TimestampParseError> {
54        let joined_at = Some(Timestamp::from_str("2015-04-26T06:26:56.936000+00:00")?);
55        let premium_since = Timestamp::from_str("2021-03-16T14:29:19.046000+00:00")?;
56        let flags = MemberFlags::BYPASSES_VERIFICATION | MemberFlags::DID_REJOIN;
57
58        let value = Member {
59            avatar: Some(image_hash::AVATAR),
60            communication_disabled_until: None,
61            deaf: false,
62            flags,
63            joined_at,
64            mute: true,
65            nick: Some("twilight".to_owned()),
66            pending: false,
67            premium_since: Some(premium_since),
68            roles: Vec::new(),
69            user: User {
70                accent_color: None,
71                avatar: None,
72                avatar_decoration: None,
73                avatar_decoration_data: None,
74                banner: None,
75                bot: false,
76                discriminator: 1,
77                email: None,
78                flags: None,
79                global_name: Some("test".to_owned()),
80                id: Id::new(3),
81                locale: None,
82                mfa_enabled: None,
83                name: "twilight".to_owned(),
84                premium_type: None,
85                public_flags: None,
86                system: None,
87                verified: None,
88            },
89        };
90
91        serde_test::assert_tokens(
92            &value,
93            &[
94                Token::Struct {
95                    name: "Member",
96                    len: 11,
97                },
98                Token::Str("avatar"),
99                Token::Some,
100                Token::Str(image_hash::AVATAR_INPUT),
101                Token::Str("communication_disabled_until"),
102                Token::None,
103                Token::Str("deaf"),
104                Token::Bool(false),
105                Token::Str("flags"),
106                Token::U64(flags.bits()),
107                Token::Str("joined_at"),
108                Token::Some,
109                Token::Str("2015-04-26T06:26:56.936000+00:00"),
110                Token::Str("mute"),
111                Token::Bool(true),
112                Token::Str("nick"),
113                Token::Some,
114                Token::Str("twilight"),
115                Token::Str("pending"),
116                Token::Bool(false),
117                Token::Str("premium_since"),
118                Token::Some,
119                Token::Str("2021-03-16T14:29:19.046000+00:00"),
120                Token::Str("roles"),
121                Token::Seq { len: Some(0) },
122                Token::SeqEnd,
123                Token::Str("user"),
124                Token::Struct {
125                    name: "User",
126                    len: 10,
127                },
128                Token::Str("accent_color"),
129                Token::None,
130                Token::Str("avatar"),
131                Token::None,
132                Token::Str("avatar_decoration"),
133                Token::None,
134                Token::Str("avatar_decoration_data"),
135                Token::None,
136                Token::Str("banner"),
137                Token::None,
138                Token::Str("bot"),
139                Token::Bool(false),
140                Token::Str("discriminator"),
141                Token::Str("0001"),
142                Token::Str("global_name"),
143                Token::Some,
144                Token::Str("test"),
145                Token::Str("id"),
146                Token::NewtypeStruct { name: "Id" },
147                Token::Str("3"),
148                Token::Str("username"),
149                Token::Str("twilight"),
150                Token::StructEnd,
151                Token::StructEnd,
152            ],
153        );
154
155        Ok(())
156    }
157
158    #[test]
159    #[allow(clippy::too_many_lines)]
160    fn guild_member_communication_disabled_until() -> Result<(), TimestampParseError> {
161        let communication_disabled_until = Timestamp::from_str("2021-12-23T14:29:19.046000+00:00")?;
162        let joined_at = Some(Timestamp::from_str("2015-04-26T06:26:56.936000+00:00")?);
163        let premium_since = Timestamp::from_str("2021-03-16T14:29:19.046000+00:00")?;
164        let flags = MemberFlags::BYPASSES_VERIFICATION | MemberFlags::DID_REJOIN;
165
166        let value = Member {
167            avatar: Some(image_hash::AVATAR),
168            communication_disabled_until: Some(communication_disabled_until),
169            deaf: false,
170            flags,
171            joined_at,
172            mute: true,
173            nick: Some("twilight".to_owned()),
174            pending: false,
175            premium_since: Some(premium_since),
176            roles: Vec::new(),
177            user: User {
178                accent_color: None,
179                avatar: None,
180                avatar_decoration: None,
181                avatar_decoration_data: None,
182                banner: None,
183                bot: false,
184                discriminator: 1,
185                email: None,
186                flags: None,
187                global_name: Some("test".to_owned()),
188                id: Id::new(3),
189                locale: None,
190                mfa_enabled: None,
191                name: "twilight".to_owned(),
192                premium_type: None,
193                public_flags: None,
194                system: None,
195                verified: None,
196            },
197        };
198
199        serde_test::assert_tokens(
200            &value,
201            &[
202                Token::Struct {
203                    name: "Member",
204                    len: 11,
205                },
206                Token::Str("avatar"),
207                Token::Some,
208                Token::Str(image_hash::AVATAR_INPUT),
209                Token::Str("communication_disabled_until"),
210                Token::Some,
211                Token::Str("2021-12-23T14:29:19.046000+00:00"),
212                Token::Str("deaf"),
213                Token::Bool(false),
214                Token::Str("flags"),
215                Token::U64(flags.bits()),
216                Token::Str("joined_at"),
217                Token::Some,
218                Token::Str("2015-04-26T06:26:56.936000+00:00"),
219                Token::Str("mute"),
220                Token::Bool(true),
221                Token::Str("nick"),
222                Token::Some,
223                Token::Str("twilight"),
224                Token::Str("pending"),
225                Token::Bool(false),
226                Token::Str("premium_since"),
227                Token::Some,
228                Token::Str("2021-03-16T14:29:19.046000+00:00"),
229                Token::Str("roles"),
230                Token::Seq { len: Some(0) },
231                Token::SeqEnd,
232                Token::Str("user"),
233                Token::Struct {
234                    name: "User",
235                    len: 10,
236                },
237                Token::Str("accent_color"),
238                Token::None,
239                Token::Str("avatar"),
240                Token::None,
241                Token::Str("avatar_decoration"),
242                Token::None,
243                Token::Str("avatar_decoration_data"),
244                Token::None,
245                Token::Str("banner"),
246                Token::None,
247                Token::Str("bot"),
248                Token::Bool(false),
249                Token::Str("discriminator"),
250                Token::Str("0001"),
251                Token::Str("global_name"),
252                Token::Some,
253                Token::Str("test"),
254                Token::Str("id"),
255                Token::NewtypeStruct { name: "Id" },
256                Token::Str("3"),
257                Token::Str("username"),
258                Token::Str("twilight"),
259                Token::StructEnd,
260                Token::StructEnd,
261            ],
262        );
263
264        Ok(())
265    }
266}