1use super::create_poll::Ready;
2#[cfg(feature = "http")]
3use super::{check_overflow, Builder};
4use super::{
5 CreateActionRow,
6 CreateAllowedMentions,
7 CreateAttachment,
8 CreateEmbed,
9 CreatePoll,
10 EditAttachments,
11};
12#[cfg(feature = "http")]
13use crate::constants;
14#[cfg(feature = "http")]
15use crate::http::CacheHttp;
16use crate::internal::prelude::*;
17use crate::model::prelude::*;
18
19#[derive(Clone, Debug)]
21pub enum CreateInteractionResponse {
22 Pong,
26 Message(CreateInteractionResponseMessage),
30 Defer(CreateInteractionResponseMessage),
35 Acknowledge,
43 UpdateMessage(CreateInteractionResponseMessage),
49 Autocomplete(CreateAutocompleteResponse),
55 Modal(CreateModal),
61 #[deprecated = "use premium button components via `CreateButton::new_premium` instead"]
68 PremiumRequired,
69 LaunchActivity,
76}
77
78impl serde::Serialize for CreateInteractionResponse {
79 #[allow(deprecated)] fn serialize<S: serde::Serializer>(&self, serializer: S) -> StdResult<S::Ok, S::Error> {
81 use serde::ser::SerializeMap as _;
82
83 let mut map = serializer.serialize_map(Some(2))?;
84 map.serialize_entry("type", &match self {
85 Self::Pong => 1,
86 Self::Message(_) => 4,
87 Self::Defer(_) => 5,
88 Self::Acknowledge => 6,
89 Self::UpdateMessage(_) => 7,
90 Self::Autocomplete(_) => 8,
91 Self::Modal(_) => 9,
92 Self::PremiumRequired => 10,
93 Self::LaunchActivity => 12,
94 })?;
95
96 match self {
97 Self::Autocomplete(x) => map.serialize_entry("data", &x)?,
98 Self::Modal(x) => map.serialize_entry("data", &x)?,
99 Self::Message(x) | Self::Defer(x) | Self::UpdateMessage(x) => {
100 map.serialize_entry("data", &x)?;
101 },
102 Self::Pong | Self::Acknowledge | Self::PremiumRequired | Self::LaunchActivity => {
103 map.serialize_entry("data", &None::<()>)?;
104 },
105 }
106
107 map.end()
108 }
109}
110
111impl CreateInteractionResponse {
112 #[cfg(feature = "http")]
113 fn check_length(&self) -> Result<()> {
114 if let CreateInteractionResponse::Message(data)
115 | CreateInteractionResponse::Defer(data)
116 | CreateInteractionResponse::UpdateMessage(data) = self
117 {
118 if let Some(content) = &data.content {
119 check_overflow(content.chars().count(), constants::MESSAGE_CODE_LIMIT)
120 .map_err(|overflow| Error::Model(ModelError::MessageTooLong(overflow)))?;
121 }
122
123 if let Some(embeds) = &data.embeds {
124 check_overflow(embeds.len(), constants::EMBED_MAX_COUNT)
125 .map_err(|_| Error::Model(ModelError::EmbedAmount))?;
126
127 for embed in embeds {
128 embed.check_length()?;
129 }
130 }
131 }
132 Ok(())
133 }
134}
135
136#[cfg(feature = "http")]
137#[async_trait::async_trait]
138impl Builder for CreateInteractionResponse {
139 type Context<'ctx> = (InteractionId, &'ctx str);
140 type Built = ();
141
142 async fn execute(
153 mut self,
154 cache_http: impl CacheHttp,
155 ctx: Self::Context<'_>,
156 ) -> Result<Self::Built> {
157 self.check_length()?;
158 let files = match &mut self {
159 CreateInteractionResponse::Message(msg)
160 | CreateInteractionResponse::Defer(msg)
161 | CreateInteractionResponse::UpdateMessage(msg) => msg.attachments.take_files(),
162 _ => Vec::new(),
163 };
164
165 let http = cache_http.http();
166 if let Self::Message(msg) | Self::Defer(msg) | Self::UpdateMessage(msg) = &mut self {
167 if msg.allowed_mentions.is_none() {
168 msg.allowed_mentions.clone_from(&http.default_allowed_mentions);
169 }
170 }
171
172 http.create_interaction_response(ctx.0, ctx.1, &self, files).await
173 }
174}
175
176#[derive(Clone, Debug, Default, Serialize)]
178#[must_use]
179pub struct CreateInteractionResponseMessage {
180 #[serde(skip_serializing_if = "Option::is_none")]
181 tts: Option<bool>,
182 #[serde(skip_serializing_if = "Option::is_none")]
183 content: Option<String>,
184 #[serde(skip_serializing_if = "Option::is_none")]
185 embeds: Option<Vec<CreateEmbed>>,
186 #[serde(skip_serializing_if = "Option::is_none")]
187 allowed_mentions: Option<CreateAllowedMentions>,
188 #[serde(skip_serializing_if = "Option::is_none")]
189 flags: Option<InteractionResponseFlags>,
190 #[serde(skip_serializing_if = "Option::is_none")]
191 components: Option<Vec<CreateActionRow>>,
192 #[serde(skip_serializing_if = "Option::is_none")]
193 poll: Option<CreatePoll<Ready>>,
194 attachments: EditAttachments,
195}
196
197impl CreateInteractionResponseMessage {
198 pub fn new() -> Self {
200 Self::default()
201 }
202
203 pub fn tts(mut self, tts: bool) -> Self {
209 self.tts = Some(tts);
210 self
211 }
212
213 pub fn add_file(mut self, file: CreateAttachment) -> Self {
215 self.attachments = self.attachments.add(file);
216 self
217 }
218
219 pub fn add_files(mut self, files: impl IntoIterator<Item = CreateAttachment>) -> Self {
221 for file in files {
222 self.attachments = self.attachments.add(file);
223 }
224 self
225 }
226
227 pub fn files(mut self, files: impl IntoIterator<Item = CreateAttachment>) -> Self {
232 self.attachments = EditAttachments::new();
233 self.add_files(files)
234 }
235
236 #[inline]
240 pub fn content(mut self, content: impl Into<String>) -> Self {
241 self.content = Some(content.into());
242 self
243 }
244
245 pub fn add_embed(mut self, embed: CreateEmbed) -> Self {
249 self.embeds.get_or_insert_with(Vec::new).push(embed);
250 self
251 }
252
253 pub fn add_embeds(mut self, embeds: Vec<CreateEmbed>) -> Self {
257 self.embeds.get_or_insert_with(Vec::new).extend(embeds);
258 self
259 }
260
261 pub fn embed(self, embed: CreateEmbed) -> Self {
266 self.embeds(vec![embed])
267 }
268
269 pub fn embeds(mut self, embeds: Vec<CreateEmbed>) -> Self {
274 self.embeds = Some(embeds);
275 self
276 }
277
278 pub fn allowed_mentions(mut self, allowed_mentions: CreateAllowedMentions) -> Self {
280 self.allowed_mentions = Some(allowed_mentions);
281 self
282 }
283
284 pub fn flags(mut self, flags: InteractionResponseFlags) -> Self {
286 self.flags = Some(flags);
287 self
288 }
289
290 pub fn ephemeral(mut self, ephemeral: bool) -> Self {
292 let mut flags = self.flags.unwrap_or_else(InteractionResponseFlags::empty);
293
294 if ephemeral {
295 flags |= InteractionResponseFlags::EPHEMERAL;
296 } else {
297 flags &= !InteractionResponseFlags::EPHEMERAL;
298 }
299
300 self.flags = Some(flags);
301 self
302 }
303
304 pub fn components(mut self, components: Vec<CreateActionRow>) -> Self {
306 self.components = Some(components);
307 self
308 }
309
310 pub fn poll(mut self, poll: CreatePoll<Ready>) -> Self {
314 self.poll = Some(poll);
315 self
316 }
317
318 super::button_and_select_menu_convenience_methods!(self.components);
319}
320
321#[must_use]
324#[derive(Clone, Debug, Deserialize, Serialize)]
325#[serde(transparent)]
326pub struct AutocompleteChoice(CommandOptionChoice);
327impl AutocompleteChoice {
328 pub fn new(name: impl Into<String>, value: impl Into<Value>) -> Self {
329 Self(CommandOptionChoice {
330 name: name.into(),
331 name_localizations: None,
332 value: value.into(),
333 })
334 }
335
336 pub fn add_localized_name(
337 mut self,
338 locale: impl Into<String>,
339 localized_name: impl Into<String>,
340 ) -> Self {
341 self.0
342 .name_localizations
343 .get_or_insert_with(Default::default)
344 .insert(locale.into(), localized_name.into());
345 self
346 }
347}
348
349impl<S: Into<String>> From<S> for AutocompleteChoice {
350 fn from(value: S) -> Self {
351 let value = value.into();
352 let name = value.clone();
353 Self::new(name, value)
354 }
355}
356
357#[derive(Clone, Debug, Default, Serialize)]
359#[must_use]
360pub struct CreateAutocompleteResponse {
361 choices: Vec<AutocompleteChoice>,
362}
363
364impl CreateAutocompleteResponse {
365 pub fn new() -> Self {
367 Self::default()
368 }
369
370 pub fn set_choices(mut self, choices: Vec<AutocompleteChoice>) -> Self {
376 self.choices = choices;
377 self
378 }
379
380 pub fn add_int_choice(self, name: impl Into<String>, value: i64) -> Self {
385 self.add_choice(AutocompleteChoice::new(name, value))
386 }
387
388 pub fn add_string_choice(self, name: impl Into<String>, value: impl Into<String>) -> Self {
393 self.add_choice(AutocompleteChoice::new(name, value.into()))
394 }
395
396 pub fn add_number_choice(self, name: impl Into<String>, value: f64) -> Self {
401 self.add_choice(AutocompleteChoice::new(name, value))
402 }
403
404 fn add_choice(mut self, value: AutocompleteChoice) -> Self {
405 self.choices.push(value);
406 self
407 }
408}
409
410#[cfg(feature = "http")]
411#[async_trait::async_trait]
412impl Builder for CreateAutocompleteResponse {
413 type Context<'ctx> = (InteractionId, &'ctx str);
414 type Built = ();
415
416 async fn execute(
422 self,
423 cache_http: impl CacheHttp,
424 ctx: Self::Context<'_>,
425 ) -> Result<Self::Built> {
426 cache_http.http().create_interaction_response(ctx.0, ctx.1, &self, Vec::new()).await
427 }
428}
429
430#[derive(Clone, Debug, Default, Serialize)]
432#[must_use]
433pub struct CreateModal {
434 components: Vec<CreateActionRow>,
435 custom_id: String,
436 title: String,
437}
438
439impl CreateModal {
440 pub fn new(custom_id: impl Into<String>, title: impl Into<String>) -> Self {
442 Self {
443 components: Vec::new(),
444 custom_id: custom_id.into(),
445 title: title.into(),
446 }
447 }
448
449 pub fn components(mut self, components: Vec<CreateActionRow>) -> Self {
453 self.components = components;
454 self
455 }
456}