1use serde::de::{Deserialize, Deserializer, Error as DeError};
2use serde::ser::{Serialize, Serializer};
3
4use super::{
5 CommandInteraction,
6 ComponentInteraction,
7 InstallationContext,
8 ModalInteraction,
9 PingInteraction,
10};
11use crate::internal::prelude::*;
12use crate::json::from_value;
13use crate::model::guild::PartialMember;
14use crate::model::id::{ApplicationId, GuildId, InteractionId, MessageId, UserId};
15use crate::model::monetization::Entitlement;
16use crate::model::user::User;
17use crate::model::utils::{deserialize_val, remove_from_map, StrOrInt};
18use crate::model::Permissions;
19
20#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
22#[derive(Clone, Debug)]
23#[non_exhaustive]
24pub enum Interaction {
25 Ping(PingInteraction),
26 Command(CommandInteraction),
27 Autocomplete(CommandInteraction),
28 Component(ComponentInteraction),
29 Modal(ModalInteraction),
30}
31
32impl Interaction {
33 #[must_use]
35 pub fn id(&self) -> InteractionId {
36 match self {
37 Self::Ping(i) => i.id,
38 Self::Command(i) | Self::Autocomplete(i) => i.id,
39 Self::Component(i) => i.id,
40 Self::Modal(i) => i.id,
41 }
42 }
43
44 #[must_use]
46 pub fn kind(&self) -> InteractionType {
47 match self {
48 Self::Ping(_) => InteractionType::Ping,
49 Self::Command(_) => InteractionType::Command,
50 Self::Component(_) => InteractionType::Component,
51 Self::Autocomplete(_) => InteractionType::Autocomplete,
52 Self::Modal(_) => InteractionType::Modal,
53 }
54 }
55
56 #[must_use]
58 pub fn app_permissions(&self) -> Option<Permissions> {
59 match self {
60 Self::Ping(_) => None,
61 Self::Command(i) | Self::Autocomplete(i) => i.app_permissions,
62 Self::Component(i) => i.app_permissions,
63 Self::Modal(i) => i.app_permissions,
64 }
65 }
66
67 #[must_use]
69 pub fn application_id(&self) -> ApplicationId {
70 match self {
71 Self::Ping(i) => i.application_id,
72 Self::Command(i) | Self::Autocomplete(i) => i.application_id,
73 Self::Component(i) => i.application_id,
74 Self::Modal(i) => i.application_id,
75 }
76 }
77
78 #[must_use]
80 pub fn token(&self) -> &str {
81 match self {
82 Self::Ping(i) => i.token.as_str(),
83 Self::Command(i) | Self::Autocomplete(i) => i.token.as_str(),
84 Self::Component(i) => i.token.as_str(),
85 Self::Modal(i) => i.token.as_str(),
86 }
87 }
88
89 #[must_use]
91 pub fn guild_locale(&self) -> Option<&str> {
92 match self {
93 Self::Ping(_) => None,
94 Self::Command(i) | Self::Autocomplete(i) => i.guild_locale.as_deref(),
95 Self::Component(i) => i.guild_locale.as_deref(),
96 Self::Modal(i) => i.guild_locale.as_deref(),
97 }
98 }
99
100 #[must_use]
102 pub fn entitlements(&self) -> Option<&[Entitlement]> {
103 match self {
104 Self::Ping(_) => None,
105 Self::Command(i) | Self::Autocomplete(i) => Some(&i.entitlements),
106 Self::Component(i) => Some(&i.entitlements),
107 Self::Modal(i) => Some(&i.entitlements),
108 }
109 }
110
111 #[must_use]
113 pub fn ping(self) -> Option<PingInteraction> {
114 match self {
115 Self::Ping(i) => Some(i),
116 _ => None,
117 }
118 }
119
120 #[must_use]
122 pub fn as_ping(&self) -> Option<&PingInteraction> {
123 match self {
124 Self::Ping(i) => Some(i),
125 _ => None,
126 }
127 }
128
129 #[must_use]
131 pub fn into_ping(self) -> Option<PingInteraction> {
132 self.ping()
133 }
134
135 #[must_use]
137 pub fn command(self) -> Option<CommandInteraction> {
138 match self {
139 Self::Command(i) => Some(i),
140 _ => None,
141 }
142 }
143
144 #[must_use]
146 pub fn as_command(&self) -> Option<&CommandInteraction> {
147 match self {
148 Self::Command(i) => Some(i),
149 _ => None,
150 }
151 }
152
153 #[must_use]
155 pub fn into_command(self) -> Option<CommandInteraction> {
156 self.command()
157 }
158
159 #[must_use]
161 pub fn message_component(self) -> Option<ComponentInteraction> {
162 match self {
163 Self::Component(i) => Some(i),
164 _ => None,
165 }
166 }
167
168 #[must_use]
170 pub fn as_message_component(&self) -> Option<&ComponentInteraction> {
171 match self {
172 Self::Component(i) => Some(i),
173 _ => None,
174 }
175 }
176
177 #[must_use]
179 pub fn into_message_component(self) -> Option<ComponentInteraction> {
180 self.message_component()
181 }
182
183 #[must_use]
185 pub fn autocomplete(self) -> Option<CommandInteraction> {
186 match self {
187 Self::Autocomplete(i) => Some(i),
188 _ => None,
189 }
190 }
191
192 #[must_use]
194 pub fn as_autocomplete(&self) -> Option<&CommandInteraction> {
195 match self {
196 Self::Autocomplete(i) => Some(i),
197 _ => None,
198 }
199 }
200
201 #[must_use]
203 pub fn into_autocomplete(self) -> Option<CommandInteraction> {
204 self.autocomplete()
205 }
206
207 #[must_use]
209 pub fn modal_submit(self) -> Option<ModalInteraction> {
210 match self {
211 Self::Modal(i) => Some(i),
212 _ => None,
213 }
214 }
215
216 #[must_use]
218 pub fn as_modal_submit(&self) -> Option<&ModalInteraction> {
219 match self {
220 Self::Modal(i) => Some(i),
221 _ => None,
222 }
223 }
224
225 #[must_use]
227 pub fn into_modal_submit(self) -> Option<ModalInteraction> {
228 self.modal_submit()
229 }
230}
231
232impl<'de> Deserialize<'de> for Interaction {
234 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> std::result::Result<Self, D::Error> {
235 let map = JsonMap::deserialize(deserializer)?;
236
237 let raw_kind = map.get("type").ok_or_else(|| DeError::missing_field("type"))?.clone();
238 let value = Value::from(map);
239
240 match deserialize_val(raw_kind)? {
241 InteractionType::Command => from_value(value).map(Interaction::Command),
242 InteractionType::Component => from_value(value).map(Interaction::Component),
243 InteractionType::Autocomplete => from_value(value).map(Interaction::Autocomplete),
244 InteractionType::Modal => from_value(value).map(Interaction::Modal),
245 InteractionType::Ping => from_value(value).map(Interaction::Ping),
246 InteractionType::Unknown(_) => return Err(DeError::custom("Unknown interaction type")),
247 }
248 .map_err(DeError::custom)
249 }
250}
251
252impl Serialize for Interaction {
253 fn serialize<S: Serializer>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error> {
254 match self {
255 Self::Ping(i) => i.serialize(serializer),
256 Self::Command(i) | Self::Autocomplete(i) => i.serialize(serializer),
257 Self::Component(i) => i.serialize(serializer),
258 Self::Modal(i) => i.serialize(serializer),
259 }
260 }
261}
262
263enum_number! {
264 #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Deserialize, Serialize)]
268 #[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
269 #[serde(from = "u8", into = "u8")]
270 #[non_exhaustive]
271 pub enum InteractionType {
272 Ping = 1,
273 Command = 2,
274 Component = 3,
275 Autocomplete = 4,
276 Modal = 5,
277 _ => Unknown(u8),
278 }
279}
280
281bitflags! {
282 #[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialEq)]
287 pub struct InteractionResponseFlags: u64 {
288 const SUPPRESS_EMBEDS = 1 << 2;
290 const EPHEMERAL = 1 << 6;
293 const SUPPRESS_NOTIFICATIONS = 1 << 12;
295 }
296}
297
298#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
302#[derive(Clone, Debug)]
303#[non_exhaustive]
304pub enum AuthorizingIntegrationOwner {
305 GuildInstall(Option<GuildId>),
309 UserInstall(UserId),
313 Unknown(InstallationContext),
314}
315
316#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
317#[derive(Clone, Debug, Default)]
318#[repr(transparent)]
319pub struct AuthorizingIntegrationOwners(pub Vec<AuthorizingIntegrationOwner>);
320
321impl<'de> serde::Deserialize<'de> for AuthorizingIntegrationOwners {
322 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
323 struct Visitor;
324
325 impl<'de> serde::de::Visitor<'de> for Visitor {
326 type Value = AuthorizingIntegrationOwners;
327
328 fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
329 formatter.write_str("a hashmap containing keys of InstallationContext and values based on those keys")
330 }
331
332 fn visit_map<A>(self, mut map: A) -> StdResult<Self::Value, A::Error>
333 where
334 A: serde::de::MapAccess<'de>,
335 {
336 let mut out = Vec::new();
337 while let Some(key_str) = map.next_key::<serde_cow::CowStr<'_>>()? {
338 let key_int = key_str.0.parse::<u8>().map_err(serde::de::Error::custom)?;
339 let value = match InstallationContext::from(key_int) {
340 InstallationContext::Guild => {
341 let id_str = map.next_value::<StrOrInt<'_>>()?;
344 let id_int = id_str.parse().map_err(A::Error::custom)?;
345 let id = std::num::NonZeroU64::new(id_int).map(GuildId::from);
346
347 AuthorizingIntegrationOwner::GuildInstall(id)
348 },
349 InstallationContext::User => {
350 AuthorizingIntegrationOwner::UserInstall(map.next_value()?)
351 },
352 key => AuthorizingIntegrationOwner::Unknown(key),
353 };
354
355 out.push(value);
356 }
357
358 Ok(AuthorizingIntegrationOwners(out))
359 }
360 }
361
362 deserializer.deserialize_map(Visitor)
363 }
364}
365
366impl serde::Serialize for AuthorizingIntegrationOwners {
367 fn serialize<S: Serializer>(&self, serializer: S) -> StdResult<S::Ok, S::Error> {
368 use serde::ser::SerializeMap;
369
370 let mut serializer = serializer.serialize_map(Some(self.0.len()))?;
371 for value in &self.0 {
372 match value {
373 AuthorizingIntegrationOwner::GuildInstall(inner) => {
374 serializer.serialize_entry(&InstallationContext::Guild, &inner)
375 },
376 AuthorizingIntegrationOwner::UserInstall(inner) => {
377 serializer.serialize_entry(&InstallationContext::User, &inner)
378 },
379 AuthorizingIntegrationOwner::Unknown(inner) => {
380 serializer.serialize_entry(&inner, &())
381 },
382 }?;
383 }
384
385 serializer.end()
386 }
387}
388
389#[cfg_attr(
395 all(not(ignore_serenity_deprecated), feature = "unstable_discord_api"),
396 deprecated = "Use Message::interaction_metadata"
397)]
398#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
399#[derive(Clone, Debug, Deserialize, Serialize)]
400#[non_exhaustive]
401pub struct MessageInteraction {
402 pub id: InteractionId,
404 #[serde(rename = "type")]
406 pub kind: InteractionType,
407 pub name: String,
411 pub user: User,
413 #[serde(skip_serializing_if = "Option::is_none")]
415 pub member: Option<PartialMember>,
416}
417
418#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
419#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
420#[non_exhaustive]
421pub struct MessageCommandInteractionMetadata {
422 pub id: InteractionId,
424 pub user: User,
426 pub authorizing_integration_owners: AuthorizingIntegrationOwners,
428 pub original_response_message_id: Option<MessageId>,
430 pub target_user: Option<User>,
432 pub target_message_id: Option<MessageId>,
435}
436
437#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
438#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
439#[non_exhaustive]
440pub struct MessageComponentInteractionMetadata {
441 pub id: InteractionId,
443 pub user: User,
445 pub authorizing_integration_owners: AuthorizingIntegrationOwners,
447 pub original_response_message_id: Option<MessageId>,
449 pub interacted_message_id: MessageId,
451}
452
453#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
454#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
455#[non_exhaustive]
456pub struct MessageModalSubmitInteractionMetadata {
457 pub id: InteractionId,
459 pub user: User,
461 pub authorizing_integration_owners: AuthorizingIntegrationOwners,
463 pub original_response_message_id: Option<MessageId>,
465 pub triggering_interaction_metadata: Box<MessageInteractionMetadata>,
467}
468
469#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
472#[derive(Clone, Debug)]
473#[non_exhaustive]
474pub enum MessageInteractionMetadata {
475 Command(MessageCommandInteractionMetadata),
476 Component(MessageComponentInteractionMetadata),
477 ModalSubmit(MessageModalSubmitInteractionMetadata),
478 Unknown(InteractionType),
479}
480
481impl<'de> serde::Deserialize<'de> for MessageInteractionMetadata {
482 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
483 let mut data = JsonMap::deserialize(deserializer)?;
484 let kind: InteractionType = remove_from_map(&mut data, "type")?;
485
486 match kind {
487 InteractionType::Command => deserialize_val(Value::from(data)).map(Self::Command),
488 InteractionType::Component => deserialize_val(Value::from(data)).map(Self::Component),
489 InteractionType::Modal => deserialize_val(Value::from(data)).map(Self::ModalSubmit),
490
491 unknown => Ok(Self::Unknown(unknown)),
492 }
493 }
494}
495
496impl serde::Serialize for MessageInteractionMetadata {
497 fn serialize<S: Serializer>(&self, serializer: S) -> StdResult<S::Ok, S::Error> {
498 #[derive(serde::Serialize)]
499 struct WithType<T> {
500 #[serde(rename = "type")]
501 kind: InteractionType,
502 #[serde(flatten)]
503 val: T,
504 }
505
506 fn serialize_with_type<S: Serializer, T: serde::Serialize>(
507 serializer: S,
508 val: T,
509 kind: InteractionType,
510 ) -> StdResult<S::Ok, S::Error> {
511 let wrapper = WithType {
512 kind,
513 val,
514 };
515
516 wrapper.serialize(serializer)
517 }
518
519 match self {
520 MessageInteractionMetadata::Command(val) => {
521 serialize_with_type(serializer, val, InteractionType::Command)
522 },
523 MessageInteractionMetadata::Component(val) => {
524 serialize_with_type(serializer, val, InteractionType::Component)
525 },
526 MessageInteractionMetadata::ModalSubmit(val) => {
527 serialize_with_type(serializer, val, InteractionType::Modal)
528 },
529 &MessageInteractionMetadata::Unknown(kind) => {
530 tracing::warn!("Tried to serialize MessageInteractionMetadata::Unknown({}), serialising null instead", u8::from(kind));
531 serializer.serialize_none()
532 },
533 }
534 }
535}