slack_blocks/elems/select/public_channel.rs
1//! # Public Channel Select
2//! [slack api docs 🔗](https://api.slack.com/reference/block-kit/block-elements#channel_select)
3//!
4//! This select menu will populate its options with a list of
5//! public channels visible to the current user in the active workspace.
6
7use std::borrow::Cow;
8
9use serde::{Deserialize, Serialize};
10#[cfg(feature = "validation")]
11use validator::Validate;
12
13#[cfg(feature = "validation")]
14use crate::val_helpr::ValidationResult;
15use crate::{compose::Confirm, text};
16
17/// # Public Channel Select
18/// [slack api docs 🔗](https://api.slack.com/reference/block-kit/block-elements#channel_select)
19///
20/// This select menu will populate its options with a list of
21/// public channels visible to the current user in the active workspace.
22#[derive(Clone, Debug, Deserialize, Hash, PartialEq, Serialize)]
23#[cfg_attr(feature = "validation", derive(Validate))]
24pub struct PublicChannel<'a> {
25 #[cfg_attr(feature = "validation",
26 validate(custom = "super::validate::placeholder"))]
27 placeholder: text::Text,
28
29 #[cfg_attr(feature = "validation", validate(length(max = 255)))]
30 action_id: Cow<'a, str>,
31
32 #[serde(skip_serializing_if = "Option::is_none")]
33 #[cfg_attr(feature = "validation", validate)]
34 confirm: Option<Confirm>,
35
36 #[serde(skip_serializing_if = "Option::is_none")]
37 initial_channel: Option<Cow<'a, str>>,
38}
39
40impl<'a> PublicChannel<'a> {
41 /// Build a new public channel select element
42 ///
43 /// # Examples
44 /// ```
45 /// use std::convert::TryFrom;
46 ///
47 /// use slack_blocks::{blocks::{Actions, Block},
48 /// compose::Opt,
49 /// elems::{select, BlockElement},
50 /// text};
51 ///
52 /// let select =
53 /// select::PublicChannel::builder().placeholder("Choose your favorite channel!")
54 /// .action_id("fave_channel")
55 /// .build();
56 ///
57 /// let block: Block = Actions::builder().element(select).build().into();
58 /// ```
59 pub fn builder() -> build::PublicChannelBuilderInit<'a> {
60 build::PublicChannelBuilderInit::new()
61 }
62
63 /// Validate that this Public Channel Select element
64 /// agrees with Slack's model requirements
65 ///
66 /// # Errors
67 /// - If `from_placeholder_and_action_id` was called with
68 /// `placeholder` longer than 150 chars
69 /// - If `from_placeholder_and_action_id` was called with
70 /// `action_id` longer than 255 chars
71 ///
72 /// # Example
73 /// ```
74 /// use slack_blocks::elems::select;
75 ///
76 /// let select = select::PublicChannel::builder().placeholder(
77 /// r#"Hey I really would appreciate it if you chose
78 /// a channel relatively soon, so that we can figure out
79 /// where we need to send this poll, ok? it's kind of
80 /// important that you specify where this poll should be
81 /// sent, in case we haven't made that super clear.
82 /// If you understand, could you pick a channel, already??"#,
83 /// )
84 /// .action_id("ABC123")
85 /// .build();
86 ///
87 /// assert!(matches!(select.validate(), Err(_)))
88 /// ```
89 #[cfg(feature = "validation")]
90 #[cfg_attr(docsrs, doc(cfg(feature = "validation")))]
91 pub fn validate(&self) -> ValidationResult {
92 Validate::validate(&self)
93 }
94}
95
96/// Public Channel Select Builder
97pub mod build {
98 use std::marker::PhantomData;
99
100 use super::*;
101 use crate::{build::*,
102 elems::select::{multi, select_kind}};
103
104 /// Required builder methods
105 #[allow(non_camel_case_types)]
106 pub mod method {
107 /// PublicChannelBuilder.placeholder
108 #[derive(Copy, Clone, Debug)]
109 pub struct placeholder;
110
111 /// PublicChannelBuilder.action_id
112 #[derive(Copy, Clone, Debug)]
113 pub struct action_id;
114 }
115
116 /// PublicChannel Select builder
117 ///
118 /// Allows you to construct a PublicChannel Select safely, with compile-time checks
119 /// on required setter methods.
120 ///
121 /// # Required Methods
122 /// `PublicChannelBuilder::build()` is only available if these methods have been called:
123 /// - `placeholder`
124 /// - `action_id`
125 ///
126 /// NOTE: I'm experimenting with an API that deviates from the `from_foo_and_bar`.
127 /// If you're a user of this library, please give me feedback in the repository
128 /// as to which pattern you like more. This will most likely be the new builder pattern
129 /// for every structure in this crate.
130 ///
131 /// # Example
132 /// ```
133 /// use std::convert::TryFrom;
134 ///
135 /// use slack_blocks::{blocks::{Actions, Block},
136 /// compose::Opt,
137 /// elems::{select::PublicChannel, BlockElement}};
138 ///
139 /// let select =
140 /// PublicChannel::builder().placeholder("Choose your favorite channel!")
141 /// .action_id("favorite_channel")
142 /// .build();
143 ///
144 /// let block: Block = Actions::builder().element(select).build().into();
145 ///
146 /// // <send block to API>
147 /// ```
148 #[derive(Debug)]
149 pub struct PublicChannelBuilder<'a, Multi, Placeholder, ActionId> {
150 placeholder: Option<text::Text>,
151 action_id: Option<Cow<'a, str>>,
152 confirm: Option<Confirm>,
153 initial_channel: Option<Cow<'a, str>>,
154 initial_channels: Option<Cow<'a, [String]>>,
155 max_selected_items: Option<u32>,
156 state: PhantomData<(Multi, Placeholder, ActionId)>,
157 }
158
159 /// Initial state for PublicChannelBuilder.
160 ///
161 /// Users will be able to choose one of the options.
162 ///
163 /// To allow choosing many, use `slack_blocks::elems::select::multi::PublicChannel::builder`.
164 pub type PublicChannelBuilderInit<'a> =
165 PublicChannelBuilder<'a,
166 select_kind::Single,
167 RequiredMethodNotCalled<method::placeholder>,
168 RequiredMethodNotCalled<method::action_id>>;
169
170 /// Initial state for PublicChannelBuilder.
171 ///
172 /// Users will be able to choose many of the options.
173 pub type MultiPublicChannelBuilderInit<'a> =
174 PublicChannelBuilder<'a,
175 select_kind::Multi,
176 RequiredMethodNotCalled<method::placeholder>,
177 RequiredMethodNotCalled<method::action_id>>;
178
179 // Methods that are always available
180 impl<'a, M, P, A> PublicChannelBuilder<'a, M, P, A> {
181 /// Construct a new PublicChannelBuilder
182 pub fn new() -> Self {
183 Self { placeholder: None,
184 action_id: None,
185 initial_channel: None,
186 initial_channels: None,
187 max_selected_items: None,
188 confirm: None,
189 state: PhantomData::<_> }
190 }
191
192 /// Change the marker type params to some other arbitrary marker type params
193 fn cast_state<P2, A2>(self) -> PublicChannelBuilder<'a, M, P2, A2> {
194 PublicChannelBuilder { placeholder: self.placeholder,
195 action_id: self.action_id,
196 confirm: self.confirm,
197 initial_channel: self.initial_channel,
198 initial_channels: self.initial_channels,
199 max_selected_items: self.max_selected_items,
200 state: PhantomData::<_> }
201 }
202
203 /// Set `placeholder` (**Required**)
204 ///
205 /// A [`plain_text` only text object 🔗] that defines
206 /// the placeholder text shown on the menu.
207 /// Maximum length for the `text` in this field is 150 characters.
208 ///
209 /// [`plain_text` only text object 🔗]: https://api.slack.comhttps://api.slack.com/reference/block-kit/composition-objects#text
210 pub fn placeholder(
211 mut self,
212 text: impl Into<text::Plain>)
213 -> PublicChannelBuilder<'a, M, Set<method::placeholder>, A> {
214 self.placeholder = Some(text.into().into());
215 self.cast_state()
216 }
217
218 /// Set `action_id` (**Required**)
219 ///
220 /// An identifier for the action triggered when a menu option is selected.
221 /// You can use this when you receive an interaction payload to [identify the source of the action 🔗].
222 /// Should be unique among all other `action_id`s used elsewhere by your app.
223 /// Maximum length for this field is 255 characters.
224 ///
225 /// [identify the source of the action 🔗]: https://api.slack.comhttps://api.slack.com/interactivity/handling#payloads
226 pub fn action_id(
227 mut self,
228 text: impl Into<Cow<'a, str>>)
229 -> PublicChannelBuilder<'a, M, P, Set<method::action_id>> {
230 self.action_id = Some(text.into());
231 self.cast_state()
232 }
233
234 /// Set `confirm` (Optional)
235 ///
236 /// A [confirm object 🔗] that defines an
237 /// optional confirmation dialog that appears after
238 /// a menu item is selected.
239 ///
240 /// [confirm object 🔗]: https://api.slack.comhttps://api.slack.com/reference/block-kit/composition-objects#confirm
241 pub fn confirm(mut self, confirm: Confirm) -> Self {
242 self.confirm = Some(confirm);
243 self
244 }
245 }
246
247 impl<'a, M, P, A> PublicChannelBuilder<'a, M, P, A> {
248 /// Set `initial_channel` (Optional)
249 ///
250 /// The ID of any valid conversation to be pre-selected when the menu loads.
251 ///
252 /// If `default_to_current_conversation` is called, this will take precedence.
253 pub fn initial_channel<S>(mut self, channel: S) -> Self
254 where S: Into<Cow<'a, str>>
255 {
256 self.initial_channel = Some(channel.into());
257 self
258 }
259
260 /// Set `initial_channel` (Optional, exclusive with `initial_channel_current`)
261 ///
262 /// A collection of IDs of any valid conversations to be pre-selected when the menu loads.
263 pub fn initial_channels<S>(mut self, channels: S) -> Self
264 where S: Into<Cow<'a, [String]>>
265 {
266 self.initial_channels = Some(channels.into());
267 self.cast_state()
268 }
269 }
270
271 impl<'a, P, A> PublicChannelBuilder<'a, select_kind::Multi, P, A> {
272 /// Set `max_selected_items` (Optional)
273 ///
274 /// Specifies the maximum number of items that can be selected in the menu.
275 ///
276 /// Minimum number is 1.
277 pub fn max_selected_items(mut self, max: u32) -> Self {
278 self.max_selected_items = Some(max);
279 self
280 }
281 }
282
283 impl<'a>
284 PublicChannelBuilder<'a,
285 select_kind::Single,
286 Set<method::placeholder>,
287 Set<method::action_id>>
288 {
289 /// All done building, now give me a darn select element!
290 ///
291 /// > `no method name 'build' found for struct 'select::static_::build::PublicChannelBuilder<...>'`?
292 /// Make sure all required setter methods have been called. See docs for `PublicChannelBuilder`.
293 ///
294 /// ```compile_fail
295 /// use slack_blocks::elems::select::PublicChannel;
296 ///
297 /// let sel = PublicChannel::builder().build(); // Won't compile!
298 /// ```
299 ///
300 /// ```
301 /// use slack_blocks::elems::select::PublicChannel;
302 ///
303 /// let sel = PublicChannel::builder().placeholder("foo")
304 /// .action_id("bar")
305 /// .build();
306 /// ```
307 pub fn build(self) -> PublicChannel<'a> {
308 PublicChannel { placeholder: self.placeholder.unwrap(),
309 action_id: self.action_id.unwrap(),
310 confirm: self.confirm,
311 initial_channel: self.initial_channel }
312 }
313 }
314
315 impl<'a>
316 PublicChannelBuilder<'a,
317 select_kind::Multi,
318 Set<method::placeholder>,
319 Set<method::action_id>>
320 {
321 /// All done building, now give me a darn select element!
322 ///
323 /// > `no method name 'build' found for struct 'select::static_::build::PublicChannelBuilder<...>'`?
324 /// Make sure all required setter methods have been called. See docs for `PublicChannelBuilder`.
325 ///
326 /// ```compile_fail
327 /// use slack_blocks::elems::select;
328 ///
329 /// let sel = select::multi::PublicChannel::builder().build(); // Won't compile!
330 /// ```
331 ///
332 /// ```
333 /// use slack_blocks::elems::select;
334 ///
335 /// let sel = select::multi::PublicChannel::builder().placeholder("foo")
336 /// .action_id("bar")
337 /// .build();
338 /// ```
339 pub fn build(self) -> multi::PublicChannel<'a> {
340 multi::PublicChannel { placeholder: self.placeholder.unwrap(),
341 action_id: self.action_id.unwrap(),
342 confirm: self.confirm,
343 initial_channels: self.initial_channels,
344 max_selected_items: self.max_selected_items }
345 }
346 }
347}