Skip to main content

twilight_util/builder/
interaction_response_data.rs

1#![allow(deprecated)]
2
3use twilight_model::{
4    application::command::CommandOptionChoice,
5    channel::message::{AllowedMentions, Component, Embed, MessageFlags},
6    http::{attachment::Attachment, interaction::InteractionResponseData},
7    poll::Poll,
8};
9
10/// Create an [`InteractionResponseData`] with a builder.
11///
12/// # Example
13/// ```
14/// use twilight_model::channel::message::{
15///     MessageFlags,
16///     component::{ActionRow, Button, ButtonStyle, Component},
17/// };
18/// use twilight_util::builder::InteractionResponseDataBuilder;
19///
20/// let component = Component::ActionRow(ActionRow {
21///     id: None,
22///     components: Vec::from([Component::Button(Button {
23///         id: None,
24///         style: ButtonStyle::Primary,
25///         emoji: None,
26///         label: Some("Button label".to_string()),
27///         custom_id: Some("button_id".to_string()),
28///         url: None,
29///         disabled: false,
30///         sku_id: None,
31///     })]),
32/// });
33///
34/// let interaction_response_data = InteractionResponseDataBuilder::new()
35///     .content("Callback message")
36///     .flags(MessageFlags::EPHEMERAL)
37///     .components([component.clone()])
38///     .build();
39///
40/// assert_eq!(interaction_response_data.components, Some(vec![component]));
41/// ```
42#[derive(Clone, Debug)]
43#[deprecated = "use the `interaction_response` builders instead"]
44#[must_use = "builders have no effect if unused"]
45pub struct InteractionResponseDataBuilder(InteractionResponseData);
46
47impl InteractionResponseDataBuilder {
48    /// Create a new builder to construct an [`InteractionResponseData`].
49    pub const fn new() -> Self {
50        Self(InteractionResponseData {
51            allowed_mentions: None,
52            attachments: None,
53            choices: None,
54            components: None,
55            content: None,
56            custom_id: None,
57            embeds: None,
58            flags: None,
59            title: None,
60            tts: None,
61            poll: None,
62        })
63    }
64
65    /// Consume the builder, returning an [`InteractionResponseData`].
66    #[must_use = "builders have no effect if unused"]
67    pub fn build(self) -> InteractionResponseData {
68        self.0
69    }
70
71    /// Set the [`AllowedMentions`] of the callback.
72    ///
73    /// Defaults to [`None`].
74    pub fn allowed_mentions(mut self, allowed_mentions: AllowedMentions) -> Self {
75        self.0.allowed_mentions = Some(allowed_mentions);
76
77        self
78    }
79
80    /// Set the attachments of the message.
81    ///
82    /// Defaults to [`None`].
83    pub fn attachments(mut self, attachments: impl IntoIterator<Item = Attachment>) -> Self {
84        self.0.attachments = Some(attachments.into_iter().collect());
85
86        self
87    }
88
89    /// Set the autocomplete choices of the response.
90    ///
91    /// Only valid when the type of the interaction is
92    /// [`ApplicationCommandAutocompleteResult`].
93    ///
94    /// [`ApplicationCommandAutocompleteResult`]: twilight_model::http::interaction::InteractionResponseType::ApplicationCommandAutocompleteResult
95    pub fn choices(mut self, choices: impl IntoIterator<Item = CommandOptionChoice>) -> Self {
96        self.0.choices = Some(choices.into_iter().collect());
97
98        self
99    }
100
101    /// Set the message [`Component`]s of the callback.
102    ///
103    /// Defaults to [`None`].
104    pub fn components(mut self, components: impl IntoIterator<Item = Component>) -> Self {
105        self.0.components = Some(components.into_iter().collect());
106
107        self
108    }
109
110    /// Set the message content of the callback.
111    ///
112    /// Defaults to [`None`].
113    pub fn content(mut self, content: impl Into<String>) -> Self {
114        self.0.content = Some(content.into());
115
116        self
117    }
118
119    /// Set the custom ID of the callback.
120    ///
121    /// Defaults to [`None`].
122    pub fn custom_id(mut self, custom_id: impl Into<String>) -> Self {
123        self.0.custom_id = Some(custom_id.into());
124
125        self
126    }
127
128    /// Set the [`Embed`]s of the callback.
129    ///
130    /// Defaults to an empty list.
131    pub fn embeds(mut self, embeds: impl IntoIterator<Item = Embed>) -> Self {
132        self.0.embeds = Some(embeds.into_iter().collect());
133
134        self
135    }
136
137    /// Set the [`MessageFlags`].
138    ///
139    /// The only supported flags are [`EPHEMERAL`] and [`SUPPRESS_EMBEDS`].
140    ///
141    /// Defaults to [`None`].
142    ///
143    /// [`EPHEMERAL`]: twilight_model::channel::message::MessageFlags::EPHEMERAL
144    /// [`SUPPRESS_EMBEDS`]: twilight_model::channel::message::MessageFlags::SUPPRESS_EMBEDS
145    pub const fn flags(mut self, flags: MessageFlags) -> Self {
146        self.0.flags = Some(flags);
147
148        self
149    }
150
151    /// Set the title of the callback.
152    ///
153    /// Defaults to [`None`].
154    pub fn title(mut self, title: impl Into<String>) -> Self {
155        self.0.title = Some(title.into());
156
157        self
158    }
159
160    /// Set whether the response has text-to-speech enabled.
161    ///
162    /// Defaults to [`None`].
163    pub const fn tts(mut self, value: bool) -> Self {
164        self.0.tts = Some(value);
165
166        self
167    }
168
169    /// Set the poll of the callback.
170    pub fn poll(mut self, poll: Poll) -> Self {
171        self.0.poll = Some(poll);
172
173        self
174    }
175}
176
177impl Default for InteractionResponseDataBuilder {
178    fn default() -> Self {
179        Self::new()
180    }
181}
182
183#[cfg(test)]
184mod tests {
185    use super::*;
186    use static_assertions::assert_impl_all;
187    use std::fmt::Debug;
188    use twilight_model::{
189        channel::message::{
190            MentionType,
191            component::{Button, ButtonStyle},
192        },
193        poll::{PollLayoutType, PollMedia},
194        util::Timestamp,
195    };
196
197    assert_impl_all!(
198        InteractionResponseDataBuilder: Clone,
199        Debug,
200        Default,
201        Send,
202        Sync
203    );
204
205    #[test]
206    fn callback_data_builder() {
207        let allowed_mentions = AllowedMentions {
208            parse: Vec::from([MentionType::Everyone]),
209            ..Default::default()
210        };
211
212        let component = Component::Button(Button {
213            style: ButtonStyle::Primary,
214            emoji: None,
215            label: Some("test label".into()),
216            custom_id: Some("test custom id".into()),
217            url: None,
218            disabled: false,
219            sku_id: None,
220            id: None,
221        });
222
223        let embed = Embed {
224            author: None,
225            color: Some(123),
226            description: Some("a description".to_owned()),
227            fields: Vec::new(),
228            footer: None,
229            image: None,
230            kind: "rich".to_owned(),
231            provider: None,
232            thumbnail: None,
233            timestamp: Some(Timestamp::from_secs(1_580_608_922).unwrap()),
234            title: Some("a title".to_owned()),
235            url: Some("https://example.com".to_owned()),
236            video: None,
237        };
238
239        let poll = Poll {
240            answers: vec![],
241            allow_multiselect: false,
242            expiry: None,
243            layout_type: PollLayoutType::Default,
244            question: PollMedia {
245                emoji: None,
246                text: Some("lorem ipsum".to_owned()),
247            },
248            results: None,
249        };
250
251        let value = InteractionResponseDataBuilder::new()
252            .allowed_mentions(allowed_mentions.clone())
253            .components([component.clone()])
254            .content("a content")
255            .embeds([embed.clone()])
256            .flags(MessageFlags::empty())
257            .tts(false)
258            .poll(poll.clone())
259            .build();
260
261        let expected = InteractionResponseData {
262            allowed_mentions: Some(allowed_mentions),
263            attachments: None,
264            choices: None,
265            components: Some(vec![component]),
266            content: Some("a content".to_owned()),
267            custom_id: None,
268            embeds: Some(vec![embed]),
269            flags: Some(MessageFlags::empty()),
270            title: None,
271            tts: Some(false),
272            poll: Some(poll),
273        };
274
275        assert_eq!(value, expected);
276    }
277}