slack_blocks/compose/
conversation_filter.rs

1//! # Filter for Conversations List
2//! [slack api docs 🔗]
3//!
4//! Provides a way to filter the list of options
5//! in a [conversations select menu 🔗] or
6//! [conversations multi-select menu 🔗].
7//!
8//! [slack api docs 🔗]: https://api.slack.com/reference/block-kit/composition-objects#filter_conversations
9//! [conversations select menu 🔗]: https://api.slack.comhttps://api.slack.com/reference/block-kit/block-elements#conversation_select
10//! [conversations multi-select menu 🔗]: https://api.slack.comhttps://api.slack.com/reference/block-kit/block-elements#conversation_multi_select
11
12use serde::{Deserialize, Serialize};
13#[cfg(feature = "validation")]
14use validator::Validate;
15
16#[cfg(feature = "validation")]
17use crate::val_helpr::ValidationResult;
18
19/// # Filter for Conversations List
20/// [slack api docs 🔗]
21///
22/// Provides a way to filter the list of options
23/// in a [conversations select menu 🔗] or
24/// [conversations multi-select menu 🔗].
25///
26/// [slack api docs 🔗]: https://api.slack.com/reference/block-kit/composition-objects#filter_conversations
27/// [conversations select menu 🔗]: https://api.slack.comhttps://api.slack.com/reference/block-kit/block-elements#conversation_select
28/// [conversations multi-select menu 🔗]: https://api.slack.comhttps://api.slack.com/reference/block-kit/block-elements#conversation_multi_select
29#[derive(Clone, Debug, Default, Deserialize, Hash, PartialEq, Serialize)]
30#[cfg_attr(feature = "validation", derive(Validate))]
31pub struct ConversationFilter {
32  #[cfg_attr(feature = "validation", validate(length(min = 1, max = 4)))]
33  #[serde(skip_serializing_if = "Option::is_none")]
34  include: Option<Vec<ConversationKind>>,
35
36  #[serde(skip_serializing_if = "Option::is_none")]
37  exclude_external_shared_channels: Option<bool>,
38
39  #[serde(skip_serializing_if = "Option::is_none")]
40  exclude_bot_users: Option<bool>,
41}
42
43impl ConversationFilter {
44  /// Create a Conversation Filter object
45  /// that allows bot users & all kinds of channels;
46  /// including cross-org shared channels.
47  ///
48  /// # Example
49  /// ```
50  /// use slack_blocks::compose::ConversationFilter;
51  ///
52  /// let filter = ConversationFilter::new();
53  /// // TODO: once conversationselect is implemented
54  /// // let select = ConversationSelect::from_filter(filter);
55  /// ```
56  pub fn new() -> Self {
57    Default::default()
58  }
59
60  /// Chainable setter method that allows you to restrict
61  /// the kinds of channels that will appear in the
62  /// conversation select menu.
63  ///
64  /// For excluding cross-org shared channels, see
65  /// `exclude_external_shared_channels`.
66  ///
67  /// For excluding DMs with bots, see `exclude_bot_users`.
68  ///
69  /// # Arguments
70  /// - `kinds` - A **non-empty** unique collection of
71  ///     `ConversationKind`s, that the select options
72  ///     will be restricted to.
73  ///
74  /// # Example
75  /// ```
76  /// use slack_blocks::compose::ConversationFilter;
77  /// use slack_blocks::compose::conversation_filter::ConversationKind;
78  ///
79  /// let filter = ConversationFilter::new()
80  ///     .include_conversation_kinds(vec![
81  ///         ConversationKind::PublicChannel,
82  ///     ]);
83  ///
84  /// // TODO: once conversationselect is implemented
85  /// // let select = ConversationSelect::from_filter(filter);
86  /// ```
87  pub fn include_conversation_kinds(mut self,
88                                    kinds: impl IntoIterator<Item = ConversationKind>)
89                                    -> Self {
90    let mut kinds: Vec<_> = kinds.into_iter().collect();
91    match kinds.len() {
92      | 0 => self,
93      | _ => {
94        kinds.dedup();
95
96        self.include = Some(kinds);
97        self
98      },
99    }
100  }
101
102  /// Chainable setter method that allows cross-org
103  /// shared channels to appear in the conversation
104  /// select menu.
105  ///
106  /// Note that this setting is the default, and that
107  /// calling this method is a no-op. It exists purely
108  /// as declarative sugar for filter construction.
109  ///
110  /// For excluding cross-org shared channels, see
111  /// `exclude_external_shared_channels`.
112  ///
113  /// # Example
114  /// ```
115  /// use slack_blocks::compose::ConversationFilter;
116  ///
117  /// let filter = ConversationFilter::new().include_external_shared_channels();
118  ///
119  /// // TODO: once conversationselect is implemented
120  /// // let select = ConversationSelect::from_filter(filter);
121  /// ```
122  pub fn include_external_shared_channels(self) -> Self {
123    self
124  }
125
126  /// Chainable setter method that prevents cross-workspace
127  /// shared channels from appearing in the conversation
128  /// select menu.
129  ///
130  /// # Example
131  /// ```
132  /// use slack_blocks::compose::ConversationFilter;
133  ///
134  /// let filter = ConversationFilter::new().exclude_external_shared_channels();
135  ///
136  /// // TODO: once conversationselect is implemented
137  /// // let select = ConversationSelect::from_filter(filter);
138  /// ```
139  pub fn exclude_external_shared_channels(mut self) -> Self {
140    self.exclude_external_shared_channels = Some(true);
141    self
142  }
143
144  /// Chainable setter method that allows conversations
145  /// with Bot Users to appear in the conversation
146  /// select menu.
147  ///
148  /// This is the default behavior.
149  ///
150  /// For excluding bot user DMs, see `exclude_bot_users`.
151  ///
152  /// # Example
153  /// ```
154  /// use slack_blocks::compose::ConversationFilter;
155  ///
156  /// let filter = ConversationFilter::new().include_bot_users();
157  ///
158  /// // TODO: once conversationselect is implemented
159  /// // let select = ConversationSelect::from_filter(filter);
160  /// ```
161  pub fn include_bot_users(self) -> Self {
162    self
163  }
164
165  /// Chainable setter method that prevents DMs with
166  /// Bot users from appearing in the conversation
167  /// select menu.
168  ///
169  /// # Example
170  /// ```
171  /// use slack_blocks::compose::ConversationFilter;
172  ///
173  /// let filter = ConversationFilter::new().exclude_bot_users();
174  ///
175  /// // TODO: once conversationselect is implemented
176  /// // let select = ConversationSelect::from_filter(filter);
177  /// ```
178  pub fn exclude_bot_users(mut self) -> Self {
179    self.exclude_bot_users = Some(true);
180    self
181  }
182
183  /// Validate that this Conversation Filter object
184  /// agrees with Slack's model requirements.
185  ///
186  /// This type has runtime checks that prevent it from
187  /// failing validation.
188  ///
189  /// # Errors
190  /// - Never
191  ///
192  /// # Example
193  /// ```
194  /// use slack_blocks::compose::ConversationFilter;
195  ///
196  /// let filter = ConversationFilter::new().include_conversation_kinds(vec![]);
197  ///
198  /// assert_eq!(false, matches!(filter.validate(), Err(_)));
199  /// ```
200  #[cfg(feature = "validation")]
201  #[cfg_attr(docsrs, doc(cfg(feature = "validation")))]
202  pub fn validate(&self) -> ValidationResult {
203    Validate::validate(self)
204  }
205}
206
207// TODO: move this somewhere else. it is 100% gonna be used elsewhere.
208/// Type of slack "conversations"; dms and channels.
209#[derive(Copy, Clone, Debug, Deserialize, Hash, PartialEq, Serialize)]
210pub enum ConversationKind {
211  /// A direct message
212  #[serde(rename = "im")]
213  Dm,
214
215  /// A group DM
216  #[serde(rename = "mpim")]
217  GroupDm,
218
219  /// A public channel
220  #[serde(rename = "public")]
221  PublicChannel,
222
223  /// A private channel
224  #[serde(rename = "private")]
225  PrivateChannel,
226}