1use crate::user::AvatarDecorationData;
2use crate::{
3 channel::{Attachment, ChannelType, Message, thread::ThreadMetadata},
4 guild::{MemberFlags, Permissions, Role},
5 id::{
6 Id,
7 marker::{AttachmentMarker, ChannelMarker, MessageMarker, RoleMarker, UserMarker},
8 },
9 user::User,
10 util::{ImageHash, Timestamp},
11};
12use serde::{Deserialize, Serialize};
13use std::collections::hash_map::HashMap;
14
15#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
22pub struct InteractionDataResolved {
23 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
25 pub attachments: HashMap<Id<AttachmentMarker>, Attachment>,
26 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
28 pub channels: HashMap<Id<ChannelMarker>, InteractionChannel>,
29 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
33 pub members: HashMap<Id<UserMarker>, InteractionMember>,
34 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
36 pub messages: HashMap<Id<MessageMarker>, Message>,
37 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
39 pub roles: HashMap<Id<RoleMarker>, Role>,
40 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
42 pub users: HashMap<Id<UserMarker>, User>,
43}
44
45#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
49pub struct InteractionChannel {
50 pub id: Id<ChannelMarker>,
52 #[serde(rename = "type")]
56 pub kind: ChannelType,
57 pub name: String,
59 #[serde(skip_serializing_if = "Option::is_none")]
61 pub parent_id: Option<Id<ChannelMarker>>,
62 pub permissions: Permissions,
64 #[serde(skip_serializing_if = "Option::is_none")]
66 pub thread_metadata: Option<ThreadMetadata>,
67}
68
69#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
73pub struct InteractionMember {
74 #[serde(skip_serializing_if = "Option::is_none")]
76 pub avatar: Option<ImageHash>,
77 #[serde(skip_serializing_if = "Option::is_none")]
79 pub avatar_decoration_data: Option<AvatarDecorationData>,
80 #[serde(skip_serializing_if = "Option::is_none")]
82 pub banner: Option<ImageHash>,
83 pub communication_disabled_until: Option<Timestamp>,
85 pub flags: MemberFlags,
89 pub joined_at: Option<Timestamp>,
91 pub nick: Option<String>,
93 pub pending: bool,
96 pub permissions: Permissions,
98 #[serde(skip_serializing_if = "Option::is_none")]
99 pub premium_since: Option<Timestamp>,
100 #[serde(default)]
102 pub roles: Vec<Id<RoleMarker>>,
103}
104
105#[cfg(test)]
106mod tests {
107 use super::{InteractionChannel, InteractionDataResolved, InteractionMember};
108 use crate::guild::RoleColors;
109 use crate::user::PrimaryGuild;
110 use crate::{
111 channel::{
112 Attachment, ChannelType, Message,
113 message::{
114 MessageFlags, MessageType,
115 sticker::{MessageSticker, StickerFormatType},
116 },
117 },
118 guild::{MemberFlags, PartialMember, Permissions, Role, RoleFlags},
119 id::Id,
120 test::image_hash,
121 user::{PremiumType, User, UserFlags},
122 util::datetime::{Timestamp, TimestampParseError},
123 };
124 use serde_test::Token;
125 use std::str::FromStr;
126
127 #[test]
128 #[allow(clippy::too_many_lines, deprecated)]
129 fn test_data_resolved() -> Result<(), TimestampParseError> {
130 let joined_at = Some(Timestamp::from_str("2021-08-10T12:18:37.000000+00:00")?);
131 let timestamp = Timestamp::from_str("2020-02-02T02:02:02.020000+00:00")?;
132 let flags = MemberFlags::BYPASSES_VERIFICATION | MemberFlags::DID_REJOIN;
133
134 let value = InteractionDataResolved {
135 attachments: IntoIterator::into_iter([(
136 Id::new(400),
137 Attachment {
138 content_type: Some("image/png".to_owned()),
139 ephemeral: true,
140 filename: "rainbow_dash.png".to_owned(),
141 flags: None,
142 description: None,
143 duration_secs: None,
144 height: Some(2674),
145 id: Id::new(400),
146 proxy_url: "https://proxy.example.com/rainbow_dash.png".to_owned(),
147 size: 13370,
148 title: None,
149 url: "https://example.com/rainbow_dash.png".to_owned(),
150 waveform: None,
151 width: Some(1337),
152 },
153 )])
154 .collect(),
155 channels: IntoIterator::into_iter([(
156 Id::new(100),
157 InteractionChannel {
158 id: Id::new(100),
159 kind: ChannelType::GuildText,
160 name: "channel name".into(),
161 parent_id: None,
162 permissions: Permissions::empty(),
163 thread_metadata: None,
164 },
165 )])
166 .collect(),
167 members: IntoIterator::into_iter([(
168 Id::new(300),
169 InteractionMember {
170 avatar: None,
171 avatar_decoration_data: None,
172 banner: None,
173 communication_disabled_until: None,
174 flags,
175 joined_at,
176 nick: None,
177 pending: false,
178 permissions: Permissions::empty(),
179 premium_since: None,
180 roles: Vec::new(),
181 },
182 )])
183 .collect(),
184 messages: IntoIterator::into_iter([(
185 Id::new(4),
186 Message {
187 activity: None,
188 application: None,
189 application_id: None,
190 attachments: Vec::new(),
191 author: User {
192 accent_color: None,
193 avatar: Some(image_hash::AVATAR),
194 avatar_decoration: None,
195 avatar_decoration_data: None,
196 banner: None,
197 bot: false,
198 discriminator: 1,
199 email: None,
200 flags: None,
201 global_name: Some("test".to_owned()),
202 id: Id::new(3),
203 locale: None,
204 mfa_enabled: None,
205 name: "test".to_owned(),
206 premium_type: None,
207 primary_guild: None,
208 public_flags: None,
209 system: None,
210 verified: None,
211 },
212 call: None,
213 channel_id: Id::new(2),
214 components: Vec::new(),
215 content: "ping".to_owned(),
216 edited_timestamp: None,
217 embeds: Vec::new(),
218 flags: Some(MessageFlags::empty()),
219 guild_id: Some(Id::new(1)),
220 id: Id::new(4),
221 interaction: None,
222 interaction_metadata: None,
223 kind: MessageType::Regular,
224 member: Some(PartialMember {
225 avatar: None,
226 avatar_decoration_data: None,
227 banner: None,
228 communication_disabled_until: None,
229 flags,
230 deaf: false,
231 joined_at,
232 mute: false,
233 nick: Some("member nick".to_owned()),
234 permissions: None,
235 premium_since: None,
236 roles: Vec::new(),
237 user: None,
238 }),
239 mention_channels: Vec::new(),
240 mention_everyone: false,
241 mention_roles: Vec::new(),
242 mentions: Vec::new(),
243 message_snapshots: Vec::new(),
244 pinned: false,
245 poll: None,
246 reactions: Vec::new(),
247 reference: None,
248 referenced_message: None,
249 role_subscription_data: None,
250 sticker_items: vec![MessageSticker {
251 format_type: StickerFormatType::Png,
252 id: Id::new(1),
253 name: "sticker name".to_owned(),
254 }],
255 timestamp,
256 thread: None,
257 tts: false,
258 webhook_id: None,
259 },
260 )])
261 .collect(),
262 roles: IntoIterator::into_iter([(
263 Id::new(400),
264 Role {
265 color: 0,
266 colors: RoleColors {
267 primary_color: 0,
268 secondary_color: None,
269 tertiary_color: None,
270 },
271 hoist: true,
272 icon: None,
273 id: Id::new(400),
274 managed: false,
275 mentionable: true,
276 name: "test".to_owned(),
277 permissions: Permissions::ADMINISTRATOR,
278 position: 12,
279 flags: RoleFlags::empty(),
280 tags: None,
281 unicode_emoji: None,
282 },
283 )])
284 .collect(),
285 users: IntoIterator::into_iter([(
286 Id::new(300),
287 User {
288 accent_color: None,
289 avatar: Some(image_hash::AVATAR),
290 avatar_decoration: None,
291 avatar_decoration_data: None,
292 banner: None,
293 bot: false,
294 discriminator: 1,
295 email: Some("address@example.com".to_owned()),
296 flags: Some(UserFlags::PREMIUM_EARLY_SUPPORTER | UserFlags::VERIFIED_DEVELOPER),
297 global_name: Some("test".to_owned()),
298 id: Id::new(300),
299 locale: Some("en-us".to_owned()),
300 mfa_enabled: Some(true),
301 name: "test".to_owned(),
302 premium_type: Some(PremiumType::Nitro),
303 primary_guild: Some(PrimaryGuild {
304 identity_guild_id: Some(Id::new(169_256_939_211_980_800)),
305 identity_enabled: Some(true),
306 tag: Some("DISC".to_owned()),
307 badge: Some("1269e74af4df7417b13759eae50c83dc".parse().unwrap()),
308 }),
309 public_flags: Some(
310 UserFlags::PREMIUM_EARLY_SUPPORTER | UserFlags::VERIFIED_DEVELOPER,
311 ),
312 system: None,
313 verified: Some(true),
314 },
315 )])
316 .collect(),
317 };
318
319 serde_test::assert_tokens(
320 &value,
321 &[
322 Token::Struct {
323 name: "InteractionDataResolved",
324 len: 6,
325 },
326 Token::Str("attachments"),
327 Token::Map { len: Some(1) },
328 Token::NewtypeStruct { name: "Id" },
329 Token::Str("400"),
330 Token::Struct {
331 name: "Attachment",
332 len: 9,
333 },
334 Token::Str("content_type"),
335 Token::Some,
336 Token::Str("image/png"),
337 Token::Str("ephemeral"),
338 Token::Bool(true),
339 Token::Str("filename"),
340 Token::Str("rainbow_dash.png"),
341 Token::Str("height"),
342 Token::Some,
343 Token::U64(2674),
344 Token::Str("id"),
345 Token::NewtypeStruct { name: "Id" },
346 Token::Str("400"),
347 Token::Str("proxy_url"),
348 Token::Str("https://proxy.example.com/rainbow_dash.png"),
349 Token::Str("size"),
350 Token::U64(13370),
351 Token::Str("url"),
352 Token::Str("https://example.com/rainbow_dash.png"),
353 Token::Str("width"),
354 Token::Some,
355 Token::U64(1337),
356 Token::StructEnd,
357 Token::MapEnd,
358 Token::Str("channels"),
359 Token::Map { len: Some(1) },
360 Token::NewtypeStruct { name: "Id" },
361 Token::Str("100"),
362 Token::Struct {
363 name: "InteractionChannel",
364 len: 4,
365 },
366 Token::Str("id"),
367 Token::NewtypeStruct { name: "Id" },
368 Token::Str("100"),
369 Token::Str("type"),
370 Token::U8(0),
371 Token::Str("name"),
372 Token::Str("channel name"),
373 Token::Str("permissions"),
374 Token::Str("0"),
375 Token::StructEnd,
376 Token::MapEnd,
377 Token::Str("members"),
378 Token::Map { len: Some(1) },
379 Token::NewtypeStruct { name: "Id" },
380 Token::Str("300"),
381 Token::Struct {
382 name: "InteractionMember",
383 len: 7,
384 },
385 Token::Str("communication_disabled_until"),
386 Token::None,
387 Token::Str("flags"),
388 Token::U64(flags.bits()),
389 Token::Str("joined_at"),
390 Token::Some,
391 Token::Str("2021-08-10T12:18:37.000000+00:00"),
392 Token::Str("nick"),
393 Token::None,
394 Token::Str("pending"),
395 Token::Bool(false),
396 Token::Str("permissions"),
397 Token::Str("0"),
398 Token::Str("roles"),
399 Token::Seq { len: Some(0) },
400 Token::SeqEnd,
401 Token::StructEnd,
402 Token::MapEnd,
403 Token::Str("messages"),
404 Token::Map { len: Some(1) },
405 Token::NewtypeStruct { name: "Id" },
406 Token::Str("4"),
407 Token::Struct {
408 name: "Message",
409 len: 19,
410 },
411 Token::Str("attachments"),
412 Token::Seq { len: Some(0) },
413 Token::SeqEnd,
414 Token::Str("author"),
415 Token::Struct {
416 name: "User",
417 len: 10,
418 },
419 Token::Str("accent_color"),
420 Token::None,
421 Token::Str("avatar"),
422 Token::Some,
423 Token::Str(image_hash::AVATAR_INPUT),
424 Token::Str("avatar_decoration"),
425 Token::None,
426 Token::Str("avatar_decoration_data"),
427 Token::None,
428 Token::Str("banner"),
429 Token::None,
430 Token::Str("bot"),
431 Token::Bool(false),
432 Token::Str("discriminator"),
433 Token::Str("0001"),
434 Token::Str("global_name"),
435 Token::Some,
436 Token::Str("test"),
437 Token::Str("id"),
438 Token::NewtypeStruct { name: "Id" },
439 Token::Str("3"),
440 Token::Str("username"),
441 Token::Str("test"),
442 Token::StructEnd,
443 Token::Str("call"),
444 Token::None,
445 Token::Str("channel_id"),
446 Token::NewtypeStruct { name: "Id" },
447 Token::Str("2"),
448 Token::Str("content"),
449 Token::Str("ping"),
450 Token::Str("edited_timestamp"),
451 Token::None,
452 Token::Str("embeds"),
453 Token::Seq { len: Some(0) },
454 Token::SeqEnd,
455 Token::Str("flags"),
456 Token::Some,
457 Token::U64(0),
458 Token::Str("guild_id"),
459 Token::Some,
460 Token::NewtypeStruct { name: "Id" },
461 Token::Str("1"),
462 Token::Str("id"),
463 Token::NewtypeStruct { name: "Id" },
464 Token::Str("4"),
465 Token::Str("type"),
466 Token::U8(0),
467 Token::Str("member"),
468 Token::Some,
469 Token::Struct {
470 name: "PartialMember",
471 len: 8,
472 },
473 Token::Str("communication_disabled_until"),
474 Token::None,
475 Token::Str("deaf"),
476 Token::Bool(false),
477 Token::Str("flags"),
478 Token::U64(flags.bits()),
479 Token::Str("joined_at"),
480 Token::Some,
481 Token::Str("2021-08-10T12:18:37.000000+00:00"),
482 Token::Str("mute"),
483 Token::Bool(false),
484 Token::Str("nick"),
485 Token::Some,
486 Token::Str("member nick"),
487 Token::Str("roles"),
488 Token::Seq { len: Some(0) },
489 Token::SeqEnd,
490 Token::Str("user"),
491 Token::None,
492 Token::StructEnd,
493 Token::Str("mention_everyone"),
494 Token::Bool(false),
495 Token::Str("mention_roles"),
496 Token::Seq { len: Some(0) },
497 Token::SeqEnd,
498 Token::Str("mentions"),
499 Token::Seq { len: Some(0) },
500 Token::SeqEnd,
501 Token::Str("pinned"),
502 Token::Bool(false),
503 Token::Str("sticker_items"),
504 Token::Seq { len: Some(1) },
505 Token::Struct {
506 name: "MessageSticker",
507 len: 3,
508 },
509 Token::Str("format_type"),
510 Token::U8(1),
511 Token::Str("id"),
512 Token::NewtypeStruct { name: "Id" },
513 Token::Str("1"),
514 Token::Str("name"),
515 Token::Str("sticker name"),
516 Token::StructEnd,
517 Token::SeqEnd,
518 Token::Str("timestamp"),
519 Token::Str("2020-02-02T02:02:02.020000+00:00"),
520 Token::Str("tts"),
521 Token::Bool(false),
522 Token::StructEnd,
523 Token::MapEnd,
524 Token::Str("roles"),
525 Token::Map { len: Some(1) },
526 Token::NewtypeStruct { name: "Id" },
527 Token::Str("400"),
528 Token::Struct {
529 name: "Role",
530 len: 10,
531 },
532 Token::Str("color"),
533 Token::U32(0),
534 Token::Str("colors"),
535 Token::Struct {
536 name: "RoleColors",
537 len: 3,
538 },
539 Token::Str("primary_color"),
540 Token::U32(0),
541 Token::Str("secondary_color"),
542 Token::None,
543 Token::Str("tertiary_color"),
544 Token::None,
545 Token::StructEnd,
546 Token::Str("hoist"),
547 Token::Bool(true),
548 Token::Str("id"),
549 Token::NewtypeStruct { name: "Id" },
550 Token::Str("400"),
551 Token::Str("managed"),
552 Token::Bool(false),
553 Token::Str("mentionable"),
554 Token::Bool(true),
555 Token::Str("name"),
556 Token::Str("test"),
557 Token::Str("permissions"),
558 Token::Str("8"),
559 Token::Str("position"),
560 Token::I64(12),
561 Token::Str("flags"),
562 Token::U64(0),
563 Token::StructEnd,
564 Token::MapEnd,
565 Token::Str("users"),
566 Token::Map { len: Some(1) },
567 Token::NewtypeStruct { name: "Id" },
568 Token::Str("300"),
569 Token::Struct {
570 name: "User",
571 len: 18,
572 },
573 Token::Str("accent_color"),
574 Token::None,
575 Token::Str("avatar"),
576 Token::Some,
577 Token::Str(image_hash::AVATAR_INPUT),
578 Token::Str("avatar_decoration"),
579 Token::None,
580 Token::Str("avatar_decoration_data"),
581 Token::None,
582 Token::Str("banner"),
583 Token::None,
584 Token::Str("bot"),
585 Token::Bool(false),
586 Token::Str("discriminator"),
587 Token::Str("0001"),
588 Token::Str("email"),
589 Token::Some,
590 Token::Str("address@example.com"),
591 Token::Str("flags"),
592 Token::Some,
593 Token::U64(131_584),
594 Token::Str("global_name"),
595 Token::Some,
596 Token::Str("test"),
597 Token::Str("id"),
598 Token::NewtypeStruct { name: "Id" },
599 Token::Str("300"),
600 Token::Str("locale"),
601 Token::Some,
602 Token::Str("en-us"),
603 Token::Str("mfa_enabled"),
604 Token::Some,
605 Token::Bool(true),
606 Token::Str("username"),
607 Token::Str("test"),
608 Token::Str("premium_type"),
609 Token::Some,
610 Token::U8(2),
611 Token::Str("primary_guild"),
612 Token::Some,
613 Token::Struct {
614 name: "PrimaryGuild",
615 len: 4,
616 },
617 Token::Str("identity_guild_id"),
618 Token::Some,
619 Token::NewtypeStruct { name: "Id" },
620 Token::Str("169256939211980800"),
621 Token::Str("identity_enabled"),
622 Token::Some,
623 Token::Bool(true),
624 Token::Str("tag"),
625 Token::Some,
626 Token::Str("DISC"),
627 Token::Str("badge"),
628 Token::Some,
629 Token::Str("1269e74af4df7417b13759eae50c83dc"),
630 Token::StructEnd,
631 Token::Str("public_flags"),
632 Token::Some,
633 Token::U64(131_584),
634 Token::Str("verified"),
635 Token::Some,
636 Token::Bool(true),
637 Token::StructEnd,
638 Token::MapEnd,
639 Token::StructEnd,
640 ],
641 );
642
643 Ok(())
644 }
645}