serenity/builder/
create_interaction_response_followup.rs

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;
16#[cfg(feature = "http")]
17use crate::internal::prelude::*;
18use crate::model::prelude::*;
19
20/// [Discord docs](https://discord.com/developers/docs/interactions/receiving-and-responding#create-followup-message)
21#[derive(Clone, Debug, Default, Serialize)]
22#[must_use]
23pub struct CreateInteractionResponseFollowup {
24    #[serde(skip_serializing_if = "Option::is_none")]
25    content: Option<String>,
26    // [Omitting username: not supported in interaction followups]
27    // [Omitting avatar_url: not supported in interaction followups]
28    #[serde(skip_serializing_if = "Option::is_none")]
29    tts: Option<bool>,
30    embeds: Vec<CreateEmbed>,
31    #[serde(skip_serializing_if = "Option::is_none")]
32    allowed_mentions: Option<CreateAllowedMentions>,
33    #[serde(skip_serializing_if = "Option::is_none")]
34    components: Option<Vec<CreateActionRow>>,
35    #[serde(skip_serializing_if = "Option::is_none")]
36    flags: Option<MessageFlags>,
37    #[serde(skip_serializing_if = "Option::is_none")]
38    poll: Option<CreatePoll<Ready>>,
39    attachments: EditAttachments,
40}
41
42impl CreateInteractionResponseFollowup {
43    /// Equivalent to [`Self::default`].
44    pub fn new() -> Self {
45        Self::default()
46    }
47
48    #[cfg(feature = "http")]
49    fn check_length(&self) -> Result<()> {
50        if let Some(content) = &self.content {
51            check_overflow(content.chars().count(), constants::MESSAGE_CODE_LIMIT)
52                .map_err(|overflow| Error::Model(ModelError::MessageTooLong(overflow)))?;
53        }
54
55        check_overflow(self.embeds.len(), constants::EMBED_MAX_COUNT)
56            .map_err(|_| Error::Model(ModelError::EmbedAmount))?;
57        for embed in &self.embeds {
58            embed.check_length()?;
59        }
60
61        Ok(())
62    }
63
64    /// Set the content of the message.
65    ///
66    /// **Note**: Message contents must be under 2000 unicode code points.
67    #[inline]
68    pub fn content(mut self, content: impl Into<String>) -> Self {
69        self.content = Some(content.into());
70        self
71    }
72
73    /// Set whether the message is text-to-speech.
74    ///
75    /// Think carefully before setting this to `true`.
76    ///
77    /// Defaults to `false`.
78    pub fn tts(mut self, tts: bool) -> Self {
79        self.tts = Some(tts);
80        self
81    }
82
83    /// Appends a file to the message.
84    pub fn add_file(mut self, file: CreateAttachment) -> Self {
85        self.attachments = self.attachments.add(file);
86        self
87    }
88
89    /// Appends a list of files to the message.
90    pub fn add_files(mut self, files: impl IntoIterator<Item = CreateAttachment>) -> Self {
91        for file in files {
92            self.attachments = self.attachments.add(file);
93        }
94        self
95    }
96
97    /// Sets a list of files to include in the message.
98    ///
99    /// Calling this multiple times will overwrite the file list. To append files, call
100    /// [`Self::add_file`] or [`Self::add_files`] instead.
101    pub fn files(mut self, files: impl IntoIterator<Item = CreateAttachment>) -> Self {
102        self.attachments = EditAttachments::new();
103        self.add_files(files)
104    }
105
106    /// Adds an embed to the message.
107    pub fn add_embed(mut self, embed: CreateEmbed) -> Self {
108        self.embeds.push(embed);
109        self
110    }
111
112    /// Adds multiple embeds to the message.
113    pub fn add_embeds(mut self, embeds: Vec<CreateEmbed>) -> Self {
114        self.embeds.extend(embeds);
115        self
116    }
117
118    /// Sets a single embed to include in the message.
119    ///
120    /// Calling this will overwrite the embed list. To append embeds, call [`Self::add_embed`]
121    /// instead.
122    pub fn embed(self, embed: CreateEmbed) -> Self {
123        self.embeds(vec![embed])
124    }
125
126    /// Sets a list of embeds to include in the message.
127    ///
128    /// Calling this multiple times will overwrite the embed list. To append embeds, call
129    /// [`Self::add_embeds`] instead.
130    pub fn embeds(mut self, embeds: Vec<CreateEmbed>) -> Self {
131        self.embeds = embeds;
132        self
133    }
134
135    /// Set the allowed mentions for the message.
136    pub fn allowed_mentions(mut self, allowed_mentions: CreateAllowedMentions) -> Self {
137        self.allowed_mentions = Some(allowed_mentions);
138        self
139    }
140
141    /// Sets the flags for the response.
142    pub fn flags(mut self, flags: MessageFlags) -> Self {
143        self.flags = Some(flags);
144        self
145    }
146
147    /// Adds or removes the ephemeral flag
148    pub fn ephemeral(mut self, ephemeral: bool) -> Self {
149        let mut flags = self.flags.unwrap_or_else(MessageFlags::empty);
150
151        if ephemeral {
152            flags |= MessageFlags::EPHEMERAL;
153        } else {
154            flags &= !MessageFlags::EPHEMERAL;
155        };
156
157        self.flags = Some(flags);
158        self
159    }
160
161    /// Adds a poll to the message. Only one poll can be added per message.
162    ///
163    /// See [`CreatePoll`] for more information on creating and configuring a poll.
164    pub fn poll(mut self, poll: CreatePoll<Ready>) -> Self {
165        self.poll = Some(poll);
166        self
167    }
168
169    /// Sets the components of this message.
170    pub fn components(mut self, components: Vec<CreateActionRow>) -> Self {
171        self.components = Some(components);
172        self
173    }
174    super::button_and_select_menu_convenience_methods!(self.components);
175}
176
177#[cfg(feature = "http")]
178#[async_trait::async_trait]
179impl Builder for CreateInteractionResponseFollowup {
180    type Context<'ctx> = (Option<MessageId>, &'ctx str);
181    type Built = Message;
182
183    /// Creates or edits a followup response to the response sent. If a [`MessageId`] is provided,
184    /// then the corresponding message will be edited. Otherwise, a new message will be created.
185    ///
186    /// **Note**: Message contents must be under 2000 unicode code points, and embeds must be under
187    /// 6000 code points.
188    ///
189    /// # Errors
190    ///
191    /// Returns [`Error::Model`] if the content is too long. May also return [`Error::Http`] if the
192    /// API returns an error, or [`Error::Json`] if there is an error in deserializing the
193    /// response.
194    async fn execute(
195        mut self,
196        cache_http: impl CacheHttp,
197        ctx: Self::Context<'_>,
198    ) -> Result<Self::Built> {
199        self.check_length()?;
200
201        let files = self.attachments.take_files();
202
203        let http = cache_http.http();
204        if self.allowed_mentions.is_none() {
205            self.allowed_mentions.clone_from(&http.default_allowed_mentions);
206        }
207
208        match ctx.0 {
209            Some(id) => http.as_ref().edit_followup_message(ctx.1, id, &self, files).await,
210            None => http.as_ref().create_followup_message(ctx.1, &self, files).await,
211        }
212    }
213}