1pub mod application_command;
8pub mod callback;
9pub mod message_component;
10pub mod modal;
11
12mod context_type;
13mod interaction_type;
14mod metadata;
15mod resolved;
16
17pub use self::{
18 context_type::InteractionContextType,
19 interaction_type::InteractionType,
20 metadata::InteractionMetadata,
21 resolved::{InteractionChannel, InteractionDataResolved, InteractionMember},
22};
23
24use self::{
25 application_command::CommandData, message_component::MessageComponentInteractionData,
26 modal::ModalInteractionData,
27};
28use crate::{
29 channel::{Channel, Message},
30 guild::{GuildFeature, PartialMember, Permissions},
31 id::{
32 AnonymizableId, Id,
33 marker::{ApplicationMarker, ChannelMarker, GuildMarker, InteractionMarker, UserMarker},
34 },
35 oauth::ApplicationIntegrationMap,
36 user::User,
37};
38use serde::{
39 Deserialize, Deserializer, Serialize,
40 de::{Error as DeError, IgnoredAny, MapAccess, Visitor},
41};
42use serde_value::{DeserializerError, Value};
43use std::fmt::{Formatter, Result as FmtResult};
44
45use super::monetization::Entitlement;
46
47#[derive(Clone, Debug, PartialEq, Serialize)]
53pub struct Interaction {
54 #[serde(skip_serializing_if = "Option::is_none")]
56 pub app_permissions: Option<Permissions>,
57 pub application_id: Id<ApplicationMarker>,
59 pub authorizing_integration_owners:
62 ApplicationIntegrationMap<AnonymizableId<GuildMarker>, Id<UserMarker>>,
63 #[serde(skip_serializing_if = "Option::is_none")]
69 pub channel: Option<Channel>,
70 #[serde(skip_serializing_if = "Option::is_none")]
76 #[deprecated(
77 note = "channel_id is deprecated in the discord API and will no be sent in the future, users should use the channel field instead."
78 )]
79 pub channel_id: Option<Id<ChannelMarker>>,
80 #[serde(skip_serializing_if = "Option::is_none")]
82 pub context: Option<InteractionContextType>,
83 #[serde(skip_serializing_if = "Option::is_none")]
94 pub data: Option<InteractionData>,
95 pub entitlements: Vec<Entitlement>,
97 #[serde(skip_serializing_if = "Option::is_none")]
99 pub guild: Option<InteractionPartialGuild>,
100 #[serde(skip_serializing_if = "Option::is_none")]
102 pub guild_id: Option<Id<GuildMarker>>,
103 #[serde(skip_serializing_if = "Option::is_none")]
107 pub guild_locale: Option<String>,
108 pub id: Id<InteractionMarker>,
110 #[serde(rename = "type")]
112 pub kind: InteractionType,
113 #[serde(skip_serializing_if = "Option::is_none")]
119 pub locale: Option<String>,
120 #[serde(skip_serializing_if = "Option::is_none")]
124 pub member: Option<PartialMember>,
125 #[serde(skip_serializing_if = "Option::is_none")]
131 pub message: Option<Message>,
132 pub token: String,
134 #[serde(skip_serializing_if = "Option::is_none")]
138 pub user: Option<User>,
139}
140
141impl Interaction {
142 pub const fn author_id(&self) -> Option<Id<UserMarker>> {
151 if let Some(user) = self.author() {
152 Some(user.id)
153 } else {
154 None
155 }
156 }
157
158 pub const fn author(&self) -> Option<&User> {
167 match self.member.as_ref() {
168 Some(member) if member.user.is_some() => member.user.as_ref(),
169 _ => self.user.as_ref(),
170 }
171 }
172
173 pub const fn is_dm(&self) -> bool {
175 self.user.is_some()
176 }
177
178 pub const fn is_guild(&self) -> bool {
180 self.member.is_some()
181 }
182}
183
184impl<'de> Deserialize<'de> for Interaction {
185 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
186 deserializer.deserialize_map(InteractionVisitor)
187 }
188}
189
190#[derive(Debug, Deserialize)]
191#[serde(field_identifier, rename_all = "snake_case")]
192enum InteractionField {
193 AppPermissions,
194 ApplicationId,
195 Context,
196 Channel,
197 ChannelId,
198 Data,
199 Entitlements,
200 Guild,
201 GuildId,
202 GuildLocale,
203 Id,
204 Locale,
205 Member,
206 Message,
207 Token,
208 Type,
209 User,
210 Version,
211 AuthorizingIntegrationOwners,
212}
213
214struct InteractionVisitor;
215
216impl<'de> Visitor<'de> for InteractionVisitor {
217 type Value = Interaction;
218
219 fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult {
220 f.write_str("enum Interaction")
221 }
222
223 #[allow(clippy::too_many_lines, deprecated)]
224 fn visit_map<V: MapAccess<'de>>(self, mut map: V) -> Result<Self::Value, V::Error> {
225 let mut app_permissions: Option<Permissions> = None;
226 let mut application_id: Option<Id<ApplicationMarker>> = None;
227 let mut channel: Option<Channel> = None;
228 let mut channel_id: Option<Id<ChannelMarker>> = None;
229 let mut context: Option<InteractionContextType> = None;
230 let mut data: Option<Value> = None;
231 let mut entitlements: Option<Vec<Entitlement>> = None;
232 let mut guild: Option<InteractionPartialGuild> = None;
233 let mut guild_id: Option<Id<GuildMarker>> = None;
234 let mut guild_locale: Option<String> = None;
235 let mut id: Option<Id<InteractionMarker>> = None;
236 let mut kind: Option<InteractionType> = None;
237 let mut locale: Option<String> = None;
238 let mut member: Option<PartialMember> = None;
239 let mut message: Option<Message> = None;
240 let mut token: Option<String> = None;
241 let mut user: Option<User> = None;
242 let mut authorizing_integration_owners: Option<
243 ApplicationIntegrationMap<AnonymizableId<GuildMarker>, Id<UserMarker>>,
244 > = None;
245
246 loop {
247 let key = match map.next_key() {
248 Ok(Some(key)) => key,
249 Ok(None) => break,
250 Err(_) => {
251 map.next_value::<IgnoredAny>()?;
252
253 continue;
254 }
255 };
256
257 match key {
258 InteractionField::AppPermissions => {
259 if app_permissions.is_some() {
260 return Err(DeError::duplicate_field("app_permissions"));
261 }
262
263 app_permissions = map.next_value()?;
264 }
265 InteractionField::ApplicationId => {
266 if application_id.is_some() {
267 return Err(DeError::duplicate_field("application_id"));
268 }
269
270 application_id = Some(map.next_value()?);
271 }
272 InteractionField::Context => {
273 if context.is_some() {
274 return Err(DeError::duplicate_field("context"));
275 }
276
277 context = map.next_value()?;
278 }
279 InteractionField::Channel => {
280 if channel.is_some() {
281 return Err(DeError::duplicate_field("channel"));
282 }
283
284 channel = map.next_value()?;
285 }
286 InteractionField::ChannelId => {
287 if channel_id.is_some() {
288 return Err(DeError::duplicate_field("channel_id"));
289 }
290
291 channel_id = map.next_value()?;
292 }
293 InteractionField::Data => {
294 if data.is_some() {
295 return Err(DeError::duplicate_field("data"));
296 }
297
298 data = map.next_value()?;
299 }
300 InteractionField::Entitlements => {
301 if entitlements.is_some() {
302 return Err(DeError::duplicate_field("entitlements"));
303 }
304
305 entitlements = map.next_value()?;
306 }
307 InteractionField::Guild => {
308 if guild.is_some() {
309 return Err(DeError::duplicate_field("guild"));
310 }
311
312 guild = map.next_value()?;
313 }
314 InteractionField::GuildId => {
315 if guild_id.is_some() {
316 return Err(DeError::duplicate_field("guild_id"));
317 }
318
319 guild_id = map.next_value()?;
320 }
321 InteractionField::GuildLocale => {
322 if guild_locale.is_some() {
323 return Err(DeError::duplicate_field("guild_locale"));
324 }
325
326 guild_locale = map.next_value()?;
327 }
328 InteractionField::Id => {
329 if id.is_some() {
330 return Err(DeError::duplicate_field("id"));
331 }
332
333 id = Some(map.next_value()?);
334 }
335 InteractionField::Locale => {
336 if locale.is_some() {
337 return Err(DeError::duplicate_field("locale"));
338 }
339
340 locale = map.next_value()?;
341 }
342 InteractionField::Member => {
343 if member.is_some() {
344 return Err(DeError::duplicate_field("member"));
345 }
346
347 member = map.next_value()?;
348 }
349 InteractionField::Message => {
350 if message.is_some() {
351 return Err(DeError::duplicate_field("message"));
352 }
353
354 message = map.next_value()?;
355 }
356 InteractionField::Token => {
357 if token.is_some() {
358 return Err(DeError::duplicate_field("token"));
359 }
360
361 token = Some(map.next_value()?);
362 }
363 InteractionField::Type => {
364 if kind.is_some() {
365 return Err(DeError::duplicate_field("kind"));
366 }
367
368 kind = Some(map.next_value()?);
369 }
370 InteractionField::User => {
371 if user.is_some() {
372 return Err(DeError::duplicate_field("user"));
373 }
374
375 user = map.next_value()?;
376 }
377 InteractionField::Version => {
378 map.next_value::<IgnoredAny>()?;
380 }
381 InteractionField::AuthorizingIntegrationOwners => {
382 if authorizing_integration_owners.is_some() {
383 return Err(DeError::duplicate_field("authorizing_integration_owners"));
384 }
385
386 authorizing_integration_owners = map.next_value()?;
387 }
388 }
389 }
390
391 let application_id =
392 application_id.ok_or_else(|| DeError::missing_field("application_id"))?;
393 let authorizing_integration_owners = authorizing_integration_owners
394 .ok_or_else(|| DeError::missing_field("authorizing_integration_owners"))?;
395 let id = id.ok_or_else(|| DeError::missing_field("id"))?;
396 let token = token.ok_or_else(|| DeError::missing_field("token"))?;
397 let kind = kind.ok_or_else(|| DeError::missing_field("kind"))?;
398
399 let data = match kind {
400 InteractionType::Ping => None,
401 InteractionType::ApplicationCommand => {
402 let data = data
403 .ok_or_else(|| DeError::missing_field("data"))?
404 .deserialize_into()
405 .map_err(DeserializerError::into_error)?;
406
407 Some(InteractionData::ApplicationCommand(data))
408 }
409 InteractionType::MessageComponent => {
410 let data = data
411 .ok_or_else(|| DeError::missing_field("data"))?
412 .deserialize_into()
413 .map_err(DeserializerError::into_error)?;
414
415 Some(InteractionData::MessageComponent(data))
416 }
417 InteractionType::ApplicationCommandAutocomplete => {
418 let data = data
419 .ok_or_else(|| DeError::missing_field("data"))?
420 .deserialize_into()
421 .map_err(DeserializerError::into_error)?;
422
423 Some(InteractionData::ApplicationCommand(data))
424 }
425 InteractionType::ModalSubmit => {
426 let data = data
427 .ok_or_else(|| DeError::missing_field("data"))?
428 .deserialize_into()
429 .map_err(DeserializerError::into_error)?;
430
431 Some(InteractionData::ModalSubmit(data))
432 }
433 };
434
435 let entitlements = entitlements.unwrap_or_default();
436
437 Ok(Self::Value {
438 app_permissions,
439 application_id,
440 authorizing_integration_owners,
441 channel,
442 channel_id,
443 context,
444 data,
445 entitlements,
446 guild,
447 guild_id,
448 guild_locale,
449 id,
450 kind,
451 locale,
452 member,
453 message,
454 token,
455 user,
456 })
457 }
458}
459
460#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
462#[non_exhaustive]
463#[serde(untagged)]
464pub enum InteractionData {
465 ApplicationCommand(Box<CommandData>),
471 MessageComponent(Box<MessageComponentInteractionData>),
475 ModalSubmit(Box<ModalInteractionData>),
479}
480
481#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize, Hash)]
489pub struct InteractionPartialGuild {
490 pub id: Option<Id<GuildMarker>>,
492 pub features: Option<Vec<GuildFeature>>,
494 pub locale: Option<String>,
495}
496
497#[cfg(test)]
498mod tests {
499 use super::{
500 Interaction, InteractionData, InteractionDataResolved, InteractionMember, InteractionType,
501 application_command::{CommandData, CommandDataOption, CommandOptionValue},
502 };
503 use crate::{
504 application::{
505 command::{CommandOptionType, CommandType},
506 monetization::{EntitlementType, entitlement::Entitlement},
507 },
508 channel::Channel,
509 guild::{MemberFlags, PartialMember, Permissions},
510 id::Id,
511 oauth::ApplicationIntegrationMap,
512 test::image_hash,
513 user::User,
514 util::datetime::{Timestamp, TimestampParseError},
515 };
516 use serde_test::Token;
517 use std::{collections::HashMap, str::FromStr};
518
519 #[test]
520 #[allow(clippy::too_many_lines, deprecated)]
521 fn test_interaction_full() -> Result<(), TimestampParseError> {
522 let joined_at = Some(Timestamp::from_str("2020-01-01T00:00:00.000000+00:00")?);
523 let flags = MemberFlags::BYPASSES_VERIFICATION | MemberFlags::DID_REJOIN;
524
525 let value = Interaction {
526 app_permissions: Some(Permissions::SEND_MESSAGES),
527 application_id: Id::new(100),
528 authorizing_integration_owners: ApplicationIntegrationMap {
529 guild: None,
530 user: None,
531 },
532 channel: Some(Channel {
533 bitrate: None,
534 guild_id: None,
535 id: Id::new(400),
536 kind: crate::channel::ChannelType::GuildText,
537 last_message_id: None,
538 last_pin_timestamp: None,
539 name: None,
540 nsfw: None,
541 owner_id: None,
542 parent_id: None,
543 permission_overwrites: None,
544 position: None,
545 rate_limit_per_user: None,
546 recipients: None,
547 rtc_region: None,
548 topic: None,
549 user_limit: None,
550 application_id: None,
551 applied_tags: None,
552 available_tags: None,
553 default_auto_archive_duration: None,
554 default_forum_layout: None,
555 default_reaction_emoji: None,
556 default_sort_order: None,
557 default_thread_rate_limit_per_user: None,
558 flags: None,
559 icon: None,
560 invitable: None,
561 managed: None,
562 member: None,
563 member_count: None,
564 message_count: None,
565 newly_created: None,
566 thread_metadata: None,
567 video_quality_mode: None,
568 }),
569 channel_id: Some(Id::new(200)),
570 context: None,
571 data: Some(InteractionData::ApplicationCommand(Box::new(CommandData {
572 guild_id: None,
573 id: Id::new(300),
574 name: "command name".into(),
575 kind: CommandType::ChatInput,
576 options: Vec::from([CommandDataOption {
577 name: "member".into(),
578 value: CommandOptionValue::User(Id::new(600)),
579 }]),
580 resolved: Some(InteractionDataResolved {
581 attachments: HashMap::new(),
582 channels: HashMap::new(),
583 members: IntoIterator::into_iter([(
584 Id::new(600),
585 InteractionMember {
586 avatar: None,
587 avatar_decoration_data: None,
588 banner: None,
589 communication_disabled_until: None,
590 flags,
591 joined_at,
592 nick: Some("nickname".into()),
593 pending: false,
594 permissions: Permissions::empty(),
595 premium_since: None,
596 roles: Vec::new(),
597 },
598 )])
599 .collect(),
600 messages: HashMap::new(),
601 roles: HashMap::new(),
602 users: IntoIterator::into_iter([(
603 Id::new(600),
604 User {
605 accent_color: None,
606 avatar: Some(image_hash::AVATAR),
607 avatar_decoration: None,
608 avatar_decoration_data: None,
609 banner: None,
610 bot: false,
611 discriminator: 1111,
612 email: None,
613 flags: None,
614 global_name: Some("test".into()),
615 id: Id::new(600),
616 locale: None,
617 mfa_enabled: None,
618 name: "username".into(),
619 premium_type: None,
620 primary_guild: None,
621 public_flags: None,
622 system: None,
623 verified: None,
624 },
625 )])
626 .collect(),
627 }),
628 target_id: None,
629 }))),
630 entitlements: vec![Entitlement {
631 application_id: Id::new(100),
632 consumed: Some(false),
633 deleted: false,
634 ends_at: None,
635 guild_id: None,
636 id: Id::new(200),
637 kind: EntitlementType::ApplicationSubscription,
638 sku_id: Id::new(300),
639 starts_at: None,
640 user_id: None,
641 }],
642 guild: None,
643 guild_id: Some(Id::new(400)),
644 guild_locale: Some("de".to_owned()),
645 id: Id::new(500),
646 kind: InteractionType::ApplicationCommand,
647 locale: Some("en-GB".to_owned()),
648 member: Some(PartialMember {
649 avatar: None,
650 avatar_decoration_data: None,
651 banner: None,
652 communication_disabled_until: None,
653 deaf: false,
654 flags,
655 joined_at,
656 mute: false,
657 nick: Some("nickname".into()),
658 permissions: Some(Permissions::empty()),
659 premium_since: None,
660 roles: Vec::new(),
661 user: Some(User {
662 accent_color: None,
663 avatar: Some(image_hash::AVATAR),
664 avatar_decoration: None,
665 avatar_decoration_data: None,
666 banner: None,
667 bot: false,
668 discriminator: 1111,
669 email: None,
670 flags: None,
671 global_name: Some("test".into()),
672 id: Id::new(600),
673 locale: None,
674 mfa_enabled: None,
675 name: "username".into(),
676 premium_type: None,
677 primary_guild: None,
678 public_flags: None,
679 system: None,
680 verified: None,
681 }),
682 }),
683 message: None,
684 token: "interaction token".into(),
685 user: None,
686 };
687
688 serde_test::assert_ser_tokens(
690 &value,
691 &[
692 Token::Struct {
693 name: "Interaction",
694 len: 14,
695 },
696 Token::Str("app_permissions"),
697 Token::Some,
698 Token::Str("2048"),
699 Token::Str("application_id"),
700 Token::NewtypeStruct { name: "Id" },
701 Token::Str("100"),
702 Token::Str("authorizing_integration_owners"),
703 Token::Struct {
704 name: "ApplicationIntegrationMap",
705 len: 0,
706 },
707 Token::StructEnd,
708 Token::Str("channel"),
709 Token::Some,
710 Token::Struct {
711 name: "Channel",
712 len: 2,
713 },
714 Token::Str("id"),
715 Token::NewtypeStruct { name: "Id" },
716 Token::Str("400"),
717 Token::Str("type"),
718 Token::U8(0),
719 Token::StructEnd,
720 Token::Str("channel_id"),
721 Token::Some,
722 Token::NewtypeStruct { name: "Id" },
723 Token::Str("200"),
724 Token::Str("data"),
725 Token::Some,
726 Token::Struct {
727 name: "CommandData",
728 len: 5,
729 },
730 Token::Str("id"),
731 Token::NewtypeStruct { name: "Id" },
732 Token::Str("300"),
733 Token::Str("name"),
734 Token::Str("command name"),
735 Token::Str("type"),
736 Token::U8(1),
737 Token::Str("options"),
738 Token::Seq { len: Some(1) },
739 Token::Struct {
740 name: "CommandDataOption",
741 len: 3,
742 },
743 Token::Str("name"),
744 Token::Str("member"),
745 Token::Str("type"),
746 Token::U8(CommandOptionType::User as u8),
747 Token::Str("value"),
748 Token::NewtypeStruct { name: "Id" },
749 Token::Str("600"),
750 Token::StructEnd,
751 Token::SeqEnd,
752 Token::Str("resolved"),
753 Token::Some,
754 Token::Struct {
755 name: "InteractionDataResolved",
756 len: 2,
757 },
758 Token::Str("members"),
759 Token::Map { len: Some(1) },
760 Token::NewtypeStruct { name: "Id" },
761 Token::Str("600"),
762 Token::Struct {
763 name: "InteractionMember",
764 len: 7,
765 },
766 Token::Str("communication_disabled_until"),
767 Token::None,
768 Token::Str("flags"),
769 Token::U64(flags.bits()),
770 Token::Str("joined_at"),
771 Token::Some,
772 Token::Str("2020-01-01T00:00:00.000000+00:00"),
773 Token::Str("nick"),
774 Token::Some,
775 Token::Str("nickname"),
776 Token::Str("pending"),
777 Token::Bool(false),
778 Token::Str("permissions"),
779 Token::Str("0"),
780 Token::Str("roles"),
781 Token::Seq { len: Some(0) },
782 Token::SeqEnd,
783 Token::StructEnd,
784 Token::MapEnd,
785 Token::Str("users"),
786 Token::Map { len: Some(1) },
787 Token::NewtypeStruct { name: "Id" },
788 Token::Str("600"),
789 Token::Struct {
790 name: "User",
791 len: 10,
792 },
793 Token::Str("accent_color"),
794 Token::None,
795 Token::Str("avatar"),
796 Token::Some,
797 Token::Str(image_hash::AVATAR_INPUT),
798 Token::Str("avatar_decoration"),
799 Token::None,
800 Token::Str("avatar_decoration_data"),
801 Token::None,
802 Token::Str("banner"),
803 Token::None,
804 Token::Str("bot"),
805 Token::Bool(false),
806 Token::Str("discriminator"),
807 Token::Str("1111"),
808 Token::Str("global_name"),
809 Token::Some,
810 Token::Str("test"),
811 Token::Str("id"),
812 Token::NewtypeStruct { name: "Id" },
813 Token::Str("600"),
814 Token::Str("username"),
815 Token::Str("username"),
816 Token::StructEnd,
817 Token::MapEnd,
818 Token::StructEnd,
819 Token::StructEnd,
820 Token::Str("entitlements"),
821 Token::Seq { len: Some(1) },
822 Token::Struct {
823 name: "Entitlement",
824 len: 6,
825 },
826 Token::Str("application_id"),
827 Token::NewtypeStruct { name: "Id" },
828 Token::Str("100"),
829 Token::Str("consumed"),
830 Token::Some,
831 Token::Bool(false),
832 Token::Str("deleted"),
833 Token::Bool(false),
834 Token::Str("id"),
835 Token::NewtypeStruct { name: "Id" },
836 Token::Str("200"),
837 Token::Str("type"),
838 Token::U8(8),
839 Token::Str("sku_id"),
840 Token::NewtypeStruct { name: "Id" },
841 Token::Str("300"),
842 Token::StructEnd,
843 Token::SeqEnd,
844 Token::Str("guild_id"),
845 Token::Some,
846 Token::NewtypeStruct { name: "Id" },
847 Token::Str("400"),
848 Token::Str("guild_locale"),
849 Token::Some,
850 Token::String("de"),
851 Token::Str("id"),
852 Token::NewtypeStruct { name: "Id" },
853 Token::Str("500"),
854 Token::Str("type"),
855 Token::U8(InteractionType::ApplicationCommand as u8),
856 Token::Str("locale"),
857 Token::Some,
858 Token::Str("en-GB"),
859 Token::Str("member"),
860 Token::Some,
861 Token::Struct {
862 name: "PartialMember",
863 len: 9,
864 },
865 Token::Str("communication_disabled_until"),
866 Token::None,
867 Token::Str("deaf"),
868 Token::Bool(false),
869 Token::Str("flags"),
870 Token::U64(flags.bits()),
871 Token::Str("joined_at"),
872 Token::Some,
873 Token::Str("2020-01-01T00:00:00.000000+00:00"),
874 Token::Str("mute"),
875 Token::Bool(false),
876 Token::Str("nick"),
877 Token::Some,
878 Token::Str("nickname"),
879 Token::Str("permissions"),
880 Token::Some,
881 Token::Str("0"),
882 Token::Str("roles"),
883 Token::Seq { len: Some(0) },
884 Token::SeqEnd,
885 Token::Str("user"),
886 Token::Some,
887 Token::Struct {
888 name: "User",
889 len: 10,
890 },
891 Token::Str("accent_color"),
892 Token::None,
893 Token::Str("avatar"),
894 Token::Some,
895 Token::Str(image_hash::AVATAR_INPUT),
896 Token::Str("avatar_decoration"),
897 Token::None,
898 Token::Str("avatar_decoration_data"),
899 Token::None,
900 Token::Str("banner"),
901 Token::None,
902 Token::Str("bot"),
903 Token::Bool(false),
904 Token::Str("discriminator"),
905 Token::Str("1111"),
906 Token::Str("global_name"),
907 Token::Some,
908 Token::Str("test"),
909 Token::Str("id"),
910 Token::NewtypeStruct { name: "Id" },
911 Token::Str("600"),
912 Token::Str("username"),
913 Token::Str("username"),
914 Token::StructEnd,
915 Token::StructEnd,
916 Token::Str("token"),
917 Token::Str("interaction token"),
918 Token::StructEnd,
919 ],
920 );
921
922 Ok(())
923 }
924}