1use super::{
2 GuildIntegrationType, IntegrationAccount, IntegrationApplication, IntegrationExpireBehavior,
3};
4use crate::{
5 id::{
6 Id,
7 marker::{GuildMarker, IntegrationMarker, RoleMarker},
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 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 #[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 primary_guild: None,
115 public_flags: None,
116 system: None,
117 verified: None,
118 }),
119 };
120
121 serde_test::assert_tokens(
122 &value,
123 &[
124 Token::Struct {
125 name: "GuildIntegration",
126 len: 15,
127 },
128 Token::Str("account"),
129 Token::Struct {
130 name: "IntegrationAccount",
131 len: 2,
132 },
133 Token::Str("id"),
134 Token::Str("abcd"),
135 Token::Str("name"),
136 Token::Str("account name"),
137 Token::StructEnd,
138 Token::Str("enable_emoticons"),
139 Token::Some,
140 Token::Bool(true),
141 Token::Str("enabled"),
142 Token::Some,
143 Token::Bool(true),
144 Token::Str("expire_behavior"),
145 Token::Some,
146 Token::U8(1),
147 Token::Str("expire_grace_period"),
148 Token::Some,
149 Token::U64(3_600),
150 Token::Str("id"),
151 Token::NewtypeStruct { name: "Id" },
152 Token::Str("2"),
153 Token::Str("type"),
154 Token::Str("discord"),
155 Token::Str("name"),
156 Token::Str("integration name"),
157 Token::Str("revoked"),
158 Token::Some,
159 Token::Bool(false),
160 Token::Str("role_id"),
161 Token::Some,
162 Token::NewtypeStruct { name: "Id" },
163 Token::Str("3"),
164 Token::Str("scopes"),
165 Token::Some,
166 Token::Seq { len: Some(2) },
167 Token::Str(scope::APPLICATIONS_COMMANDS),
168 Token::Str(scope::BOT),
169 Token::SeqEnd,
170 Token::Str("subscriber_count"),
171 Token::Some,
172 Token::U64(1337),
173 Token::Str("synced_at"),
174 Token::Some,
175 Token::Str("2021-01-01T01:01:01.000000+00:00"),
176 Token::Str("syncing"),
177 Token::Some,
178 Token::Bool(false),
179 Token::Str("user"),
180 Token::Some,
181 Token::Struct {
182 name: "User",
183 len: 10,
184 },
185 Token::Str("accent_color"),
186 Token::None,
187 Token::Str("avatar"),
188 Token::Some,
189 Token::Str(image_hash::AVATAR_INPUT),
190 Token::Str("avatar_decoration"),
191 Token::None,
192 Token::Str("avatar_decoration_data"),
193 Token::None,
194 Token::Str("banner"),
195 Token::None,
196 Token::Str("bot"),
197 Token::Bool(true),
198 Token::Str("discriminator"),
199 Token::Str("1000"),
200 Token::Str("global_name"),
201 Token::Some,
202 Token::Str("test"),
203 Token::Str("id"),
204 Token::NewtypeStruct { name: "Id" },
205 Token::Str("4"),
206 Token::Str("username"),
207 Token::Str("user"),
208 Token::StructEnd,
209 Token::StructEnd,
210 ],
211 );
212
213 Ok(())
214 }
215
216 #[allow(clippy::too_many_lines)]
217 #[test]
218 fn guild_integration_complete() -> Result<(), TimestampParseError> {
219 let synced_at = Timestamp::from_str("2021-01-01T01:01:01+00:00")?;
220
221 let value = GuildIntegration {
222 account: IntegrationAccount {
223 id: "abcd".to_owned(),
224 name: "account name".to_owned(),
225 },
226 application: Some(IntegrationApplication {
227 bot: None,
228 description: "Friendship is Magic".to_string(),
229 icon: None,
230 id: Id::new(123),
231 name: "Twilight".to_string(),
232 }),
233 enable_emoticons: Some(true),
234 enabled: None,
235 expire_behavior: Some(IntegrationExpireBehavior::Kick),
236 expire_grace_period: Some(3_600),
237 guild_id: None,
238 id: Id::new(2),
239 kind: GuildIntegrationType::Discord,
240 name: "integration name".to_owned(),
241 revoked: Some(false),
242 role_id: Some(Id::new(3)),
243 scopes: Some(Vec::from([
244 scope::APPLICATIONS_COMMANDS.to_owned(),
245 scope::BOT.to_owned(),
246 ])),
247 subscriber_count: Some(1337),
248 synced_at: Some(synced_at),
249 syncing: Some(false),
250 user: Some(User {
251 accent_color: None,
252 avatar: Some(image_hash::AVATAR),
253 avatar_decoration: None,
254 avatar_decoration_data: None,
255 banner: None,
256 bot: true,
257 discriminator: 1000,
258 email: None,
259 flags: None,
260 global_name: Some("test".to_owned()),
261 id: Id::new(4),
262 locale: None,
263 mfa_enabled: None,
264 name: "user".to_owned(),
265 premium_type: None,
266 primary_guild: None,
267 public_flags: None,
268 system: None,
269 verified: None,
270 }),
271 };
272
273 serde_test::assert_tokens(
274 &value,
275 &[
276 Token::Struct {
277 name: "GuildIntegration",
278 len: 16,
279 },
280 Token::Str("account"),
281 Token::Struct {
282 name: "IntegrationAccount",
283 len: 2,
284 },
285 Token::Str("id"),
286 Token::Str("abcd"),
287 Token::Str("name"),
288 Token::Str("account name"),
289 Token::StructEnd,
290 Token::Str("application"),
291 Token::Some,
292 Token::Struct {
293 name: "IntegrationApplication",
294 len: 4,
295 },
296 Token::Str("description"),
297 Token::Str("Friendship is Magic"),
298 Token::Str("icon"),
299 Token::None,
300 Token::Str("id"),
301 Token::NewtypeStruct { name: "Id" },
302 Token::Str("123"),
303 Token::Str("name"),
304 Token::Str("Twilight"),
305 Token::StructEnd,
306 Token::Str("enable_emoticons"),
307 Token::Some,
308 Token::Bool(true),
309 Token::Str("enabled"),
310 Token::None,
311 Token::Str("expire_behavior"),
312 Token::Some,
313 Token::U8(1),
314 Token::Str("expire_grace_period"),
315 Token::Some,
316 Token::U64(3_600),
317 Token::Str("id"),
318 Token::NewtypeStruct { name: "Id" },
319 Token::Str("2"),
320 Token::Str("type"),
321 Token::Str("discord"),
322 Token::Str("name"),
323 Token::Str("integration name"),
324 Token::Str("revoked"),
325 Token::Some,
326 Token::Bool(false),
327 Token::Str("role_id"),
328 Token::Some,
329 Token::NewtypeStruct { name: "Id" },
330 Token::Str("3"),
331 Token::Str("scopes"),
332 Token::Some,
333 Token::Seq { len: Some(2) },
334 Token::Str(scope::APPLICATIONS_COMMANDS),
335 Token::Str(scope::BOT),
336 Token::SeqEnd,
337 Token::Str("subscriber_count"),
338 Token::Some,
339 Token::U64(1337),
340 Token::Str("synced_at"),
341 Token::Some,
342 Token::Str("2021-01-01T01:01:01.000000+00:00"),
343 Token::Str("syncing"),
344 Token::Some,
345 Token::Bool(false),
346 Token::Str("user"),
347 Token::Some,
348 Token::Struct {
349 name: "User",
350 len: 10,
351 },
352 Token::Str("accent_color"),
353 Token::None,
354 Token::Str("avatar"),
355 Token::Some,
356 Token::Str(image_hash::AVATAR_INPUT),
357 Token::Str("avatar_decoration"),
358 Token::None,
359 Token::Str("avatar_decoration_data"),
360 Token::None,
361 Token::Str("banner"),
362 Token::None,
363 Token::Str("bot"),
364 Token::Bool(true),
365 Token::Str("discriminator"),
366 Token::Str("1000"),
367 Token::Str("global_name"),
368 Token::Some,
369 Token::Str("test"),
370 Token::Str("id"),
371 Token::NewtypeStruct { name: "Id" },
372 Token::Str("4"),
373 Token::Str("username"),
374 Token::Str("user"),
375 Token::StructEnd,
376 Token::StructEnd,
377 ],
378 );
379
380 Ok(())
381 }
382}