twilight_model/guild/
integration.rs

1use super::{
2    GuildIntegrationType, IntegrationAccount, IntegrationApplication, IntegrationExpireBehavior,
3};
4use crate::{
5    id::{
6        marker::{GuildMarker, IntegrationMarker, RoleMarker},
7        Id,
8    },
9    user::User,
10    util::Timestamp,
11};
12use serde::{Deserialize, Serialize};
13
14#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
15pub struct GuildIntegration {
16    pub account: IntegrationAccount,
17    #[serde(skip_serializing_if = "Option::is_none")]
18    pub application: Option<IntegrationApplication>,
19    #[serde(skip_serializing_if = "Option::is_none")]
20    pub enable_emoticons: Option<bool>,
21    /// Whether the integration has been enabled.
22    ///
23    /// May be provided on some non-Discord application integrations.
24    pub enabled: Option<bool>,
25    #[serde(skip_serializing_if = "Option::is_none")]
26    pub expire_behavior: Option<IntegrationExpireBehavior>,
27    #[serde(skip_serializing_if = "Option::is_none")]
28    pub expire_grace_period: Option<u64>,
29    #[serde(skip_serializing_if = "Option::is_none")]
30    pub guild_id: Option<Id<GuildMarker>>,
31    pub id: Id<IntegrationMarker>,
32    #[serde(rename = "type")]
33    pub kind: GuildIntegrationType,
34    pub name: String,
35    #[serde(skip_serializing_if = "Option::is_none")]
36    pub revoked: Option<bool>,
37    #[serde(skip_serializing_if = "Option::is_none")]
38    pub role_id: Option<Id<RoleMarker>>,
39    /// An array of [OAuth2 scopes] which the application has been authorized for.
40    ///
41    /// [OAuth2 scopes]: crate::oauth::scope
42    #[serde(skip_serializing_if = "Option::is_none")]
43    pub scopes: Option<Vec<String>>,
44    #[serde(skip_serializing_if = "Option::is_none")]
45    pub subscriber_count: Option<u64>,
46    #[serde(skip_serializing_if = "Option::is_none")]
47    pub synced_at: Option<Timestamp>,
48    #[serde(skip_serializing_if = "Option::is_none")]
49    pub syncing: Option<bool>,
50    #[serde(skip_serializing_if = "Option::is_none")]
51    pub user: Option<User>,
52}
53
54#[cfg(test)]
55mod tests {
56    use super::{
57        GuildIntegration, IntegrationAccount, IntegrationApplication, IntegrationExpireBehavior,
58        User,
59    };
60    use crate::{
61        guild::GuildIntegrationType,
62        id::Id,
63        oauth::scope,
64        test::image_hash,
65        util::datetime::{Timestamp, TimestampParseError},
66    };
67    use serde_test::Token;
68    use std::str::FromStr;
69
70    #[allow(clippy::too_many_lines)]
71    #[test]
72    fn guild_integration() -> Result<(), TimestampParseError> {
73        let synced_at = Timestamp::from_str("2021-01-01T01:01:01+00:00")?;
74
75        let value = GuildIntegration {
76            account: IntegrationAccount {
77                id: "abcd".to_owned(),
78                name: "account name".to_owned(),
79            },
80            application: None,
81            enable_emoticons: Some(true),
82            enabled: Some(true),
83            expire_behavior: Some(IntegrationExpireBehavior::Kick),
84            expire_grace_period: Some(3_600),
85            guild_id: None,
86            id: Id::new(2),
87            kind: GuildIntegrationType::Discord,
88            name: "integration name".to_owned(),
89            revoked: Some(false),
90            role_id: Some(Id::new(3)),
91            scopes: Some(Vec::from([
92                scope::APPLICATIONS_COMMANDS.to_owned(),
93                scope::BOT.to_owned(),
94            ])),
95            subscriber_count: Some(1337),
96            synced_at: Some(synced_at),
97            syncing: Some(false),
98            user: Some(User {
99                accent_color: None,
100                avatar: Some(image_hash::AVATAR),
101                avatar_decoration: None,
102                avatar_decoration_data: None,
103                banner: None,
104                bot: true,
105                discriminator: 1000,
106                email: None,
107                flags: None,
108                global_name: Some("test".to_owned()),
109                id: Id::new(4),
110                locale: None,
111                mfa_enabled: None,
112                name: "user".to_owned(),
113                premium_type: None,
114                public_flags: None,
115                system: None,
116                verified: None,
117            }),
118        };
119
120        serde_test::assert_tokens(
121            &value,
122            &[
123                Token::Struct {
124                    name: "GuildIntegration",
125                    len: 15,
126                },
127                Token::Str("account"),
128                Token::Struct {
129                    name: "IntegrationAccount",
130                    len: 2,
131                },
132                Token::Str("id"),
133                Token::Str("abcd"),
134                Token::Str("name"),
135                Token::Str("account name"),
136                Token::StructEnd,
137                Token::Str("enable_emoticons"),
138                Token::Some,
139                Token::Bool(true),
140                Token::Str("enabled"),
141                Token::Some,
142                Token::Bool(true),
143                Token::Str("expire_behavior"),
144                Token::Some,
145                Token::U8(1),
146                Token::Str("expire_grace_period"),
147                Token::Some,
148                Token::U64(3_600),
149                Token::Str("id"),
150                Token::NewtypeStruct { name: "Id" },
151                Token::Str("2"),
152                Token::Str("type"),
153                Token::Str("discord"),
154                Token::Str("name"),
155                Token::Str("integration name"),
156                Token::Str("revoked"),
157                Token::Some,
158                Token::Bool(false),
159                Token::Str("role_id"),
160                Token::Some,
161                Token::NewtypeStruct { name: "Id" },
162                Token::Str("3"),
163                Token::Str("scopes"),
164                Token::Some,
165                Token::Seq { len: Some(2) },
166                Token::Str(scope::APPLICATIONS_COMMANDS),
167                Token::Str(scope::BOT),
168                Token::SeqEnd,
169                Token::Str("subscriber_count"),
170                Token::Some,
171                Token::U64(1337),
172                Token::Str("synced_at"),
173                Token::Some,
174                Token::Str("2021-01-01T01:01:01.000000+00:00"),
175                Token::Str("syncing"),
176                Token::Some,
177                Token::Bool(false),
178                Token::Str("user"),
179                Token::Some,
180                Token::Struct {
181                    name: "User",
182                    len: 10,
183                },
184                Token::Str("accent_color"),
185                Token::None,
186                Token::Str("avatar"),
187                Token::Some,
188                Token::Str(image_hash::AVATAR_INPUT),
189                Token::Str("avatar_decoration"),
190                Token::None,
191                Token::Str("avatar_decoration_data"),
192                Token::None,
193                Token::Str("banner"),
194                Token::None,
195                Token::Str("bot"),
196                Token::Bool(true),
197                Token::Str("discriminator"),
198                Token::Str("1000"),
199                Token::Str("global_name"),
200                Token::Some,
201                Token::Str("test"),
202                Token::Str("id"),
203                Token::NewtypeStruct { name: "Id" },
204                Token::Str("4"),
205                Token::Str("username"),
206                Token::Str("user"),
207                Token::StructEnd,
208                Token::StructEnd,
209            ],
210        );
211
212        Ok(())
213    }
214
215    #[allow(clippy::too_many_lines)]
216    #[test]
217    fn guild_integration_complete() -> Result<(), TimestampParseError> {
218        let synced_at = Timestamp::from_str("2021-01-01T01:01:01+00:00")?;
219
220        let value = GuildIntegration {
221            account: IntegrationAccount {
222                id: "abcd".to_owned(),
223                name: "account name".to_owned(),
224            },
225            application: Some(IntegrationApplication {
226                bot: None,
227                description: "Friendship is Magic".to_string(),
228                icon: None,
229                id: Id::new(123),
230                name: "Twilight".to_string(),
231            }),
232            enable_emoticons: Some(true),
233            enabled: None,
234            expire_behavior: Some(IntegrationExpireBehavior::Kick),
235            expire_grace_period: Some(3_600),
236            guild_id: None,
237            id: Id::new(2),
238            kind: GuildIntegrationType::Discord,
239            name: "integration name".to_owned(),
240            revoked: Some(false),
241            role_id: Some(Id::new(3)),
242            scopes: Some(Vec::from([
243                scope::APPLICATIONS_COMMANDS.to_owned(),
244                scope::BOT.to_owned(),
245            ])),
246            subscriber_count: Some(1337),
247            synced_at: Some(synced_at),
248            syncing: Some(false),
249            user: Some(User {
250                accent_color: None,
251                avatar: Some(image_hash::AVATAR),
252                avatar_decoration: None,
253                avatar_decoration_data: None,
254                banner: None,
255                bot: true,
256                discriminator: 1000,
257                email: None,
258                flags: None,
259                global_name: Some("test".to_owned()),
260                id: Id::new(4),
261                locale: None,
262                mfa_enabled: None,
263                name: "user".to_owned(),
264                premium_type: None,
265                public_flags: None,
266                system: None,
267                verified: None,
268            }),
269        };
270
271        serde_test::assert_tokens(
272            &value,
273            &[
274                Token::Struct {
275                    name: "GuildIntegration",
276                    len: 16,
277                },
278                Token::Str("account"),
279                Token::Struct {
280                    name: "IntegrationAccount",
281                    len: 2,
282                },
283                Token::Str("id"),
284                Token::Str("abcd"),
285                Token::Str("name"),
286                Token::Str("account name"),
287                Token::StructEnd,
288                Token::Str("application"),
289                Token::Some,
290                Token::Struct {
291                    name: "IntegrationApplication",
292                    len: 4,
293                },
294                Token::Str("description"),
295                Token::Str("Friendship is Magic"),
296                Token::Str("icon"),
297                Token::None,
298                Token::Str("id"),
299                Token::NewtypeStruct { name: "Id" },
300                Token::Str("123"),
301                Token::Str("name"),
302                Token::Str("Twilight"),
303                Token::StructEnd,
304                Token::Str("enable_emoticons"),
305                Token::Some,
306                Token::Bool(true),
307                Token::Str("enabled"),
308                Token::None,
309                Token::Str("expire_behavior"),
310                Token::Some,
311                Token::U8(1),
312                Token::Str("expire_grace_period"),
313                Token::Some,
314                Token::U64(3_600),
315                Token::Str("id"),
316                Token::NewtypeStruct { name: "Id" },
317                Token::Str("2"),
318                Token::Str("type"),
319                Token::Str("discord"),
320                Token::Str("name"),
321                Token::Str("integration name"),
322                Token::Str("revoked"),
323                Token::Some,
324                Token::Bool(false),
325                Token::Str("role_id"),
326                Token::Some,
327                Token::NewtypeStruct { name: "Id" },
328                Token::Str("3"),
329                Token::Str("scopes"),
330                Token::Some,
331                Token::Seq { len: Some(2) },
332                Token::Str(scope::APPLICATIONS_COMMANDS),
333                Token::Str(scope::BOT),
334                Token::SeqEnd,
335                Token::Str("subscriber_count"),
336                Token::Some,
337                Token::U64(1337),
338                Token::Str("synced_at"),
339                Token::Some,
340                Token::Str("2021-01-01T01:01:01.000000+00:00"),
341                Token::Str("syncing"),
342                Token::Some,
343                Token::Bool(false),
344                Token::Str("user"),
345                Token::Some,
346                Token::Struct {
347                    name: "User",
348                    len: 10,
349                },
350                Token::Str("accent_color"),
351                Token::None,
352                Token::Str("avatar"),
353                Token::Some,
354                Token::Str(image_hash::AVATAR_INPUT),
355                Token::Str("avatar_decoration"),
356                Token::None,
357                Token::Str("avatar_decoration_data"),
358                Token::None,
359                Token::Str("banner"),
360                Token::None,
361                Token::Str("bot"),
362                Token::Bool(true),
363                Token::Str("discriminator"),
364                Token::Str("1000"),
365                Token::Str("global_name"),
366                Token::Some,
367                Token::Str("test"),
368                Token::Str("id"),
369                Token::NewtypeStruct { name: "Id" },
370                Token::Str("4"),
371                Token::Str("username"),
372                Token::Str("user"),
373                Token::StructEnd,
374                Token::StructEnd,
375            ],
376        );
377
378        Ok(())
379    }
380}