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