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}