slack_morphism/models/blocks/
kit.rs

1use rsb_derive::Builder;
2use rvstruct::ValueStruct;
3use serde::{Deserialize, Serialize};
4use serde_with::skip_serializing_none;
5use url::Url;
6
7use crate::*;
8
9#[skip_serializing_none]
10#[derive(Debug, PartialEq, Clone, Eq, Hash, Serialize, Deserialize, ValueStruct)]
11pub struct SlackBlockId(pub String);
12
13#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
14#[serde(tag = "type")]
15pub enum SlackBlock {
16    #[serde(rename = "section")]
17    Section(SlackSectionBlock),
18    #[serde(rename = "header")]
19    Header(SlackHeaderBlock),
20    #[serde(rename = "divider")]
21    Divider(SlackDividerBlock),
22    #[serde(rename = "image")]
23    Image(SlackImageBlock),
24    #[serde(rename = "actions")]
25    Actions(SlackActionsBlock),
26    #[serde(rename = "context")]
27    Context(SlackContextBlock),
28    #[serde(rename = "input")]
29    Input(SlackInputBlock),
30    #[serde(rename = "file")]
31    File(SlackFileBlock),
32    #[serde(rename = "video")]
33    Video(SlackVideoBlock),
34    #[serde(rename = "markdown")]
35    Markdown(SlackMarkdownBlock),
36
37    // This block is still undocumented, so we don't define any structure yet we can return it back,
38    #[serde(rename = "rich_text")]
39    RichText(serde_json::Value),
40    #[serde(rename = "share_shortcut")]
41    ShareShortcut(serde_json::Value),
42    #[serde(rename = "event")]
43    Event(serde_json::Value),
44}
45
46#[skip_serializing_none]
47#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
48pub struct SlackSectionBlock {
49    pub block_id: Option<SlackBlockId>,
50    pub text: Option<SlackBlockText>,
51    pub fields: Option<Vec<SlackBlockText>>,
52    pub accessory: Option<SlackSectionBlockElement>,
53}
54
55impl From<SlackSectionBlock> for SlackBlock {
56    fn from(block: SlackSectionBlock) -> Self {
57        SlackBlock::Section(block)
58    }
59}
60
61#[skip_serializing_none]
62#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
63pub struct SlackHeaderBlock {
64    pub block_id: Option<SlackBlockId>,
65    pub text: SlackBlockPlainTextOnly,
66}
67
68impl From<SlackHeaderBlock> for SlackBlock {
69    fn from(block: SlackHeaderBlock) -> Self {
70        SlackBlock::Header(block)
71    }
72}
73
74#[skip_serializing_none]
75#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
76pub struct SlackDividerBlock {
77    pub block_id: Option<SlackBlockId>,
78}
79
80impl From<SlackDividerBlock> for SlackBlock {
81    fn from(block: SlackDividerBlock) -> Self {
82        SlackBlock::Divider(block)
83    }
84}
85
86#[skip_serializing_none]
87#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
88pub struct SlackImageBlock {
89    pub block_id: Option<SlackBlockId>,
90    #[serde(flatten)]
91    pub image_url_or_file: SlackImageUrlOrFile,
92    pub alt_text: String,
93    pub title: Option<SlackBlockPlainTextOnly>,
94}
95
96impl From<SlackImageBlock> for SlackBlock {
97    fn from(block: SlackImageBlock) -> Self {
98        SlackBlock::Image(block)
99    }
100}
101
102#[skip_serializing_none]
103#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
104pub struct SlackActionsBlock {
105    pub block_id: Option<SlackBlockId>,
106    pub elements: Vec<SlackActionBlockElement>,
107}
108
109impl From<SlackActionsBlock> for SlackBlock {
110    fn from(block: SlackActionsBlock) -> Self {
111        SlackBlock::Actions(block)
112    }
113}
114
115#[skip_serializing_none]
116#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
117pub struct SlackContextBlock {
118    pub block_id: Option<SlackBlockId>,
119    pub elements: Vec<SlackContextBlockElement>,
120}
121
122impl From<SlackContextBlock> for SlackBlock {
123    fn from(block: SlackContextBlock) -> Self {
124        SlackBlock::Context(block)
125    }
126}
127
128#[skip_serializing_none]
129#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
130pub struct SlackInputBlock {
131    pub block_id: Option<SlackBlockId>,
132    pub label: SlackBlockPlainTextOnly,
133    pub element: SlackInputBlockElement,
134    pub hint: Option<SlackBlockPlainTextOnly>,
135    pub optional: Option<bool>,
136    pub dispatch_action: Option<bool>,
137}
138
139impl From<SlackInputBlock> for SlackBlock {
140    fn from(block: SlackInputBlock) -> Self {
141        SlackBlock::Input(block)
142    }
143}
144
145const SLACK_FILE_BLOCK_SOURCE_DEFAULT: &str = "remote";
146
147#[skip_serializing_none]
148#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
149pub struct SlackFileBlock {
150    pub block_id: Option<SlackBlockId>,
151    pub external_id: String,
152    #[default = "SLACK_FILE_BLOCK_SOURCE_DEFAULT.into()"]
153    pub source: String,
154}
155
156impl From<SlackFileBlock> for SlackBlock {
157    fn from(block: SlackFileBlock) -> Self {
158        SlackBlock::File(block)
159    }
160}
161
162#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
163#[serde(tag = "type")]
164pub enum SlackSectionBlockElement {
165    #[serde(rename = "image")]
166    Image(SlackBlockImageElement),
167    #[serde(rename = "button")]
168    Button(SlackBlockButtonElement),
169    #[serde(rename = "static_select")]
170    StaticSelect(SlackBlockStaticSelectElement),
171    #[serde(rename = "multi_static_select")]
172    MultiStaticSelect(SlackBlockMultiStaticSelectElement),
173    #[serde(rename = "external_select")]
174    ExternalSelect(SlackBlockExternalSelectElement),
175    #[serde(rename = "multi_external_select")]
176    MultiExternalSelect(SlackBlockMultiExternalSelectElement),
177    #[serde(rename = "users_select")]
178    UsersSelect(SlackBlockUsersSelectElement),
179    #[serde(rename = "multi_users_select")]
180    MultiUsersSelect(SlackBlockMultiUsersSelectElement),
181    #[serde(rename = "conversations_select")]
182    ConversationsSelect(SlackBlockConversationsSelectElement),
183    #[serde(rename = "multi_conversations_select")]
184    MultiConversationsSelect(SlackBlockMultiConversationsSelectElement),
185    #[serde(rename = "channels_select")]
186    ChannelsSelect(SlackBlockChannelsSelectElement),
187    #[serde(rename = "multi_channels_select")]
188    MultiChannelsSelect(SlackBlockMultiChannelsSelectElement),
189    #[serde(rename = "overflow")]
190    Overflow(SlackBlockOverflowElement),
191    #[serde(rename = "datepicker")]
192    DatePicker(SlackBlockDatePickerElement),
193    #[serde(rename = "timepicker")]
194    TimePicker(SlackBlockTimePickerElement),
195    #[serde(rename = "plain_text_input")]
196    PlainTextInput(SlackBlockPlainTextInputElement),
197    #[serde(rename = "number_input")]
198    NumberInput(SlackBlockNumberInputElement),
199    #[serde(rename = "url_text_input")]
200    UrlInput(SlackBlockUrlInputElement),
201    #[serde(rename = "radio_buttons")]
202    RadioButtons(SlackBlockRadioButtonsElement),
203    #[serde(rename = "checkboxes")]
204    Checkboxes(SlackBlockCheckboxesElement),
205}
206
207#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
208#[serde(tag = "type")]
209pub enum SlackActionBlockElement {
210    #[serde(rename = "button")]
211    Button(SlackBlockButtonElement),
212    #[serde(rename = "overflow")]
213    Overflow(SlackBlockOverflowElement),
214    #[serde(rename = "datepicker")]
215    DatePicker(SlackBlockDatePickerElement),
216    #[serde(rename = "timepicker")]
217    TimePicker(SlackBlockTimePickerElement),
218    #[serde(rename = "datetimepicker")]
219    DateTimePicker(SlackBlockDateTimePickerElement),
220    #[serde(rename = "plain_text_input")]
221    PlainTextInput(SlackBlockPlainTextInputElement),
222    #[serde(rename = "number_input")]
223    NumberInput(SlackBlockNumberInputElement),
224    #[serde(rename = "url_text_input")]
225    UrlInput(SlackBlockUrlInputElement),
226    #[serde(rename = "radio_buttons")]
227    RadioButtons(SlackBlockRadioButtonsElement),
228    #[serde(rename = "checkboxes")]
229    Checkboxes(SlackBlockCheckboxesElement),
230    #[serde(rename = "static_select")]
231    StaticSelect(SlackBlockStaticSelectElement),
232    #[serde(rename = "external_select")]
233    ExternalSelect(SlackBlockExternalSelectElement),
234    #[serde(rename = "users_select")]
235    UsersSelect(SlackBlockUsersSelectElement),
236    #[serde(rename = "conversations_select")]
237    ConversationsSelect(SlackBlockConversationsSelectElement),
238    #[serde(rename = "channels_select")]
239    ChannelsSelect(SlackBlockChannelsSelectElement),
240}
241
242#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
243#[serde(tag = "type")]
244pub enum SlackContextBlockElement {
245    #[serde(rename = "image")]
246    Image(SlackBlockImageElement),
247    #[serde(rename = "plain_text")]
248    Plain(SlackBlockPlainText),
249    #[serde(rename = "mrkdwn")]
250    MarkDown(SlackBlockMarkDownText),
251}
252
253#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
254#[serde(tag = "type")]
255pub enum SlackInputBlockElement {
256    #[serde(rename = "static_select")]
257    StaticSelect(SlackBlockStaticSelectElement),
258    #[serde(rename = "multi_static_select")]
259    MultiStaticSelect(SlackBlockMultiStaticSelectElement),
260    #[serde(rename = "external_select")]
261    ExternalSelect(SlackBlockExternalSelectElement),
262    #[serde(rename = "multi_external_select")]
263    MultiExternalSelect(SlackBlockMultiExternalSelectElement),
264    #[serde(rename = "users_select")]
265    UsersSelect(SlackBlockUsersSelectElement),
266    #[serde(rename = "multi_users_select")]
267    MultiUsersSelect(SlackBlockMultiUsersSelectElement),
268    #[serde(rename = "conversations_select")]
269    ConversationsSelect(SlackBlockConversationsSelectElement),
270    #[serde(rename = "multi_conversations_select")]
271    MultiConversationsSelect(SlackBlockMultiConversationsSelectElement),
272    #[serde(rename = "channels_select")]
273    ChannelsSelect(SlackBlockChannelsSelectElement),
274    #[serde(rename = "multi_channels_select")]
275    MultiChannelsSelect(SlackBlockMultiChannelsSelectElement),
276    #[serde(rename = "datepicker")]
277    DatePicker(SlackBlockDatePickerElement),
278    #[serde(rename = "timepicker")]
279    TimePicker(SlackBlockTimePickerElement),
280    #[serde(rename = "datetimepicker")]
281    DateTimePicker(SlackBlockDateTimePickerElement),
282    #[serde(rename = "plain_text_input")]
283    PlainTextInput(SlackBlockPlainTextInputElement),
284    #[serde(rename = "number_input")]
285    NumberInput(SlackBlockNumberInputElement),
286    #[serde(rename = "url_text_input")]
287    UrlInput(SlackBlockUrlInputElement),
288    #[serde(rename = "radio_buttons")]
289    RadioButtons(SlackBlockRadioButtonsElement),
290    #[serde(rename = "checkboxes")]
291    Checkboxes(SlackBlockCheckboxesElement),
292    #[serde(rename = "email_text_input")]
293    EmailInput(SlackBlockEmailInputElement),
294}
295
296#[skip_serializing_none]
297#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
298pub struct SlackBlockImageElement {
299    #[serde(flatten)]
300    pub image_url_or_file: SlackImageUrlOrFile,
301    pub alt_text: String,
302}
303
304impl From<SlackBlockImageElement> for SlackSectionBlockElement {
305    fn from(element: SlackBlockImageElement) -> Self {
306        SlackSectionBlockElement::Image(element)
307    }
308}
309
310impl From<SlackBlockImageElement> for SlackContextBlockElement {
311    fn from(element: SlackBlockImageElement) -> Self {
312        SlackContextBlockElement::Image(element)
313    }
314}
315
316#[skip_serializing_none]
317#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
318pub struct SlackBlockButtonElement {
319    pub action_id: SlackActionId,
320    pub text: SlackBlockPlainTextOnly,
321    pub url: Option<Url>,
322    pub value: Option<String>,
323    pub style: Option<String>,
324    pub confirm: Option<SlackBlockConfirmItem>,
325}
326
327impl From<SlackBlockButtonElement> for SlackSectionBlockElement {
328    fn from(element: SlackBlockButtonElement) -> Self {
329        SlackSectionBlockElement::Button(element)
330    }
331}
332
333impl From<SlackBlockButtonElement> for SlackActionBlockElement {
334    fn from(element: SlackBlockButtonElement) -> Self {
335        SlackActionBlockElement::Button(element)
336    }
337}
338
339#[skip_serializing_none]
340#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
341pub struct SlackBlockConfirmItem {
342    pub title: SlackBlockPlainTextOnly,
343    pub text: SlackBlockText,
344    pub confirm: SlackBlockPlainTextOnly,
345    pub deny: SlackBlockPlainTextOnly,
346    pub style: Option<String>,
347}
348
349#[skip_serializing_none]
350#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
351pub struct SlackBlockChoiceItem<T: Into<SlackBlockText>> {
352    pub text: T,
353    pub value: String,
354    pub url: Option<Url>,
355}
356
357#[skip_serializing_none]
358#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
359pub struct SlackBlockOptionGroup<T: Into<SlackBlockText>> {
360    pub label: SlackBlockPlainTextOnly,
361    pub options: Vec<SlackBlockChoiceItem<T>>,
362}
363
364#[skip_serializing_none]
365#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
366pub struct SlackBlockStaticSelectElement {
367    pub action_id: SlackActionId,
368    pub placeholder: Option<SlackBlockPlainTextOnly>,
369    pub options: Option<Vec<SlackBlockChoiceItem<SlackBlockPlainTextOnly>>>,
370    pub option_groups: Option<Vec<SlackBlockOptionGroup<SlackBlockPlainTextOnly>>>,
371    pub initial_option: Option<SlackBlockChoiceItem<SlackBlockPlainTextOnly>>,
372    pub confirm: Option<SlackBlockConfirmItem>,
373    pub focus_on_load: Option<bool>,
374}
375
376impl From<SlackBlockStaticSelectElement> for SlackSectionBlockElement {
377    fn from(element: SlackBlockStaticSelectElement) -> Self {
378        SlackSectionBlockElement::StaticSelect(element)
379    }
380}
381
382impl From<SlackBlockStaticSelectElement> for SlackInputBlockElement {
383    fn from(element: SlackBlockStaticSelectElement) -> Self {
384        SlackInputBlockElement::StaticSelect(element)
385    }
386}
387
388impl From<SlackBlockStaticSelectElement> for SlackActionBlockElement {
389    fn from(element: SlackBlockStaticSelectElement) -> Self {
390        SlackActionBlockElement::StaticSelect(element)
391    }
392}
393
394#[skip_serializing_none]
395#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
396pub struct SlackBlockMultiStaticSelectElement {
397    pub action_id: SlackActionId,
398    pub placeholder: Option<SlackBlockPlainTextOnly>,
399    pub options: Option<Vec<SlackBlockChoiceItem<SlackBlockPlainTextOnly>>>,
400    pub option_groups: Option<Vec<SlackBlockOptionGroup<SlackBlockPlainTextOnly>>>,
401    pub initial_options: Option<Vec<SlackBlockChoiceItem<SlackBlockPlainTextOnly>>>,
402    pub confirm: Option<SlackBlockConfirmItem>,
403    pub max_selected_items: Option<u64>,
404    pub focus_on_load: Option<bool>,
405}
406
407impl From<SlackBlockMultiStaticSelectElement> for SlackSectionBlockElement {
408    fn from(element: SlackBlockMultiStaticSelectElement) -> Self {
409        SlackSectionBlockElement::MultiStaticSelect(element)
410    }
411}
412
413impl From<SlackBlockMultiStaticSelectElement> for SlackInputBlockElement {
414    fn from(element: SlackBlockMultiStaticSelectElement) -> Self {
415        SlackInputBlockElement::MultiStaticSelect(element)
416    }
417}
418
419#[skip_serializing_none]
420#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
421pub struct SlackBlockExternalSelectElement {
422    pub action_id: SlackActionId,
423    pub placeholder: Option<SlackBlockPlainTextOnly>,
424    pub initial_option: Option<SlackBlockChoiceItem<SlackBlockPlainTextOnly>>,
425    pub confirm: Option<SlackBlockConfirmItem>,
426    pub focus_on_load: Option<bool>,
427    pub min_query_length: Option<u64>,
428}
429
430impl From<SlackBlockExternalSelectElement> for SlackSectionBlockElement {
431    fn from(element: SlackBlockExternalSelectElement) -> Self {
432        SlackSectionBlockElement::ExternalSelect(element)
433    }
434}
435
436impl From<SlackBlockExternalSelectElement> for SlackInputBlockElement {
437    fn from(element: SlackBlockExternalSelectElement) -> Self {
438        SlackInputBlockElement::ExternalSelect(element)
439    }
440}
441
442impl From<SlackBlockExternalSelectElement> for SlackActionBlockElement {
443    fn from(element: SlackBlockExternalSelectElement) -> Self {
444        SlackActionBlockElement::ExternalSelect(element)
445    }
446}
447
448#[skip_serializing_none]
449#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
450pub struct SlackBlockMultiExternalSelectElement {
451    pub action_id: SlackActionId,
452    pub placeholder: Option<SlackBlockPlainTextOnly>,
453    pub initial_options: Option<Vec<SlackBlockChoiceItem<SlackBlockPlainTextOnly>>>,
454    pub confirm: Option<SlackBlockConfirmItem>,
455    pub max_selected_items: Option<u64>,
456    pub focus_on_load: Option<bool>,
457    pub min_query_length: Option<u64>,
458}
459
460impl From<SlackBlockMultiExternalSelectElement> for SlackSectionBlockElement {
461    fn from(element: SlackBlockMultiExternalSelectElement) -> Self {
462        SlackSectionBlockElement::MultiExternalSelect(element)
463    }
464}
465
466impl From<SlackBlockMultiExternalSelectElement> for SlackInputBlockElement {
467    fn from(element: SlackBlockMultiExternalSelectElement) -> Self {
468        SlackInputBlockElement::MultiExternalSelect(element)
469    }
470}
471
472#[skip_serializing_none]
473#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
474pub struct SlackBlockUsersSelectElement {
475    pub action_id: SlackActionId,
476    pub placeholder: Option<SlackBlockPlainTextOnly>,
477    pub initial_user: Option<String>,
478    pub confirm: Option<SlackBlockConfirmItem>,
479    pub focus_on_load: Option<bool>,
480}
481
482impl From<SlackBlockUsersSelectElement> for SlackSectionBlockElement {
483    fn from(element: SlackBlockUsersSelectElement) -> Self {
484        SlackSectionBlockElement::UsersSelect(element)
485    }
486}
487
488impl From<SlackBlockUsersSelectElement> for SlackInputBlockElement {
489    fn from(element: SlackBlockUsersSelectElement) -> Self {
490        SlackInputBlockElement::UsersSelect(element)
491    }
492}
493
494impl From<SlackBlockUsersSelectElement> for SlackActionBlockElement {
495    fn from(element: SlackBlockUsersSelectElement) -> Self {
496        SlackActionBlockElement::UsersSelect(element)
497    }
498}
499
500#[skip_serializing_none]
501#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
502pub struct SlackBlockMultiUsersSelectElement {
503    pub action_id: SlackActionId,
504    pub placeholder: Option<SlackBlockPlainTextOnly>,
505    pub initial_users: Option<Vec<String>>,
506    pub confirm: Option<SlackBlockConfirmItem>,
507    pub max_selected_items: Option<u64>,
508    pub focus_on_load: Option<bool>,
509}
510
511impl From<SlackBlockMultiUsersSelectElement> for SlackSectionBlockElement {
512    fn from(element: SlackBlockMultiUsersSelectElement) -> Self {
513        SlackSectionBlockElement::MultiUsersSelect(element)
514    }
515}
516
517impl From<SlackBlockMultiUsersSelectElement> for SlackInputBlockElement {
518    fn from(element: SlackBlockMultiUsersSelectElement) -> Self {
519        SlackInputBlockElement::MultiUsersSelect(element)
520    }
521}
522
523#[skip_serializing_none]
524#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
525pub struct SlackBlockConversationsSelectElement {
526    pub action_id: SlackActionId,
527    pub placeholder: Option<SlackBlockPlainTextOnly>,
528    pub initial_conversation: Option<SlackConversationId>,
529    pub default_to_current_conversation: Option<bool>,
530    pub confirm: Option<SlackBlockConfirmItem>,
531    pub response_url_enabled: Option<bool>,
532    pub focus_on_load: Option<bool>,
533}
534
535impl From<SlackBlockConversationsSelectElement> for SlackSectionBlockElement {
536    fn from(element: SlackBlockConversationsSelectElement) -> Self {
537        SlackSectionBlockElement::ConversationsSelect(element)
538    }
539}
540
541impl From<SlackBlockConversationsSelectElement> for SlackInputBlockElement {
542    fn from(element: SlackBlockConversationsSelectElement) -> Self {
543        SlackInputBlockElement::ConversationsSelect(element)
544    }
545}
546
547impl From<SlackBlockConversationsSelectElement> for SlackActionBlockElement {
548    fn from(element: SlackBlockConversationsSelectElement) -> Self {
549        SlackActionBlockElement::ConversationsSelect(element)
550    }
551}
552
553#[skip_serializing_none]
554#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
555pub struct SlackBlockMultiConversationsSelectElement {
556    pub action_id: SlackActionId,
557    pub placeholder: Option<SlackBlockPlainTextOnly>,
558    pub initial_conversations: Option<Vec<SlackConversationId>>,
559    pub default_to_current_conversation: Option<bool>,
560    pub confirm: Option<SlackBlockConfirmItem>,
561    pub max_selected_items: Option<u64>,
562    pub focus_on_load: Option<bool>,
563}
564
565impl From<SlackBlockMultiConversationsSelectElement> for SlackSectionBlockElement {
566    fn from(element: SlackBlockMultiConversationsSelectElement) -> Self {
567        SlackSectionBlockElement::MultiConversationsSelect(element)
568    }
569}
570
571impl From<SlackBlockMultiConversationsSelectElement> for SlackInputBlockElement {
572    fn from(element: SlackBlockMultiConversationsSelectElement) -> Self {
573        SlackInputBlockElement::MultiConversationsSelect(element)
574    }
575}
576
577#[skip_serializing_none]
578#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
579pub struct SlackBlockChannelsSelectElement {
580    pub action_id: SlackActionId,
581    pub placeholder: Option<SlackBlockPlainTextOnly>,
582    pub initial_channel: Option<SlackChannelId>,
583    pub confirm: Option<SlackBlockConfirmItem>,
584    pub response_url_enabled: Option<bool>,
585    pub focus_on_load: Option<bool>,
586}
587
588impl From<SlackBlockChannelsSelectElement> for SlackSectionBlockElement {
589    fn from(element: SlackBlockChannelsSelectElement) -> Self {
590        SlackSectionBlockElement::ChannelsSelect(element)
591    }
592}
593
594impl From<SlackBlockChannelsSelectElement> for SlackInputBlockElement {
595    fn from(element: SlackBlockChannelsSelectElement) -> Self {
596        SlackInputBlockElement::ChannelsSelect(element)
597    }
598}
599
600impl From<SlackBlockChannelsSelectElement> for SlackActionBlockElement {
601    fn from(element: SlackBlockChannelsSelectElement) -> Self {
602        SlackActionBlockElement::ChannelsSelect(element)
603    }
604}
605
606#[skip_serializing_none]
607#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
608pub struct SlackBlockMultiChannelsSelectElement {
609    pub action_id: SlackActionId,
610    pub placeholder: Option<SlackBlockPlainTextOnly>,
611    pub initial_channels: Option<Vec<SlackChannelId>>,
612    pub confirm: Option<SlackBlockConfirmItem>,
613    pub max_selected_items: Option<u64>,
614    pub focus_on_load: Option<bool>,
615}
616
617impl From<SlackBlockMultiChannelsSelectElement> for SlackSectionBlockElement {
618    fn from(element: SlackBlockMultiChannelsSelectElement) -> Self {
619        SlackSectionBlockElement::MultiChannelsSelect(element)
620    }
621}
622
623impl From<SlackBlockMultiChannelsSelectElement> for SlackInputBlockElement {
624    fn from(element: SlackBlockMultiChannelsSelectElement) -> Self {
625        SlackInputBlockElement::MultiChannelsSelect(element)
626    }
627}
628
629#[skip_serializing_none]
630#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
631pub struct SlackBlockOverflowElement {
632    pub action_id: SlackActionId,
633    pub options: Vec<SlackBlockChoiceItem<SlackBlockPlainTextOnly>>,
634    pub confirm: Option<SlackBlockConfirmItem>,
635}
636
637impl From<SlackBlockOverflowElement> for SlackSectionBlockElement {
638    fn from(element: SlackBlockOverflowElement) -> Self {
639        SlackSectionBlockElement::Overflow(element)
640    }
641}
642
643impl From<SlackBlockOverflowElement> for SlackActionBlockElement {
644    fn from(element: SlackBlockOverflowElement) -> Self {
645        SlackActionBlockElement::Overflow(element)
646    }
647}
648
649#[skip_serializing_none]
650#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
651pub struct SlackBlockDatePickerElement {
652    pub action_id: SlackActionId,
653    pub placeholder: Option<SlackBlockPlainTextOnly>,
654    pub initial_date: Option<String>,
655    pub confirm: Option<SlackBlockConfirmItem>,
656    pub focus_on_load: Option<bool>,
657}
658
659impl From<SlackBlockDatePickerElement> for SlackSectionBlockElement {
660    fn from(element: SlackBlockDatePickerElement) -> Self {
661        SlackSectionBlockElement::DatePicker(element)
662    }
663}
664
665impl From<SlackBlockDatePickerElement> for SlackInputBlockElement {
666    fn from(element: SlackBlockDatePickerElement) -> Self {
667        SlackInputBlockElement::DatePicker(element)
668    }
669}
670
671impl From<SlackBlockDatePickerElement> for SlackActionBlockElement {
672    fn from(element: SlackBlockDatePickerElement) -> Self {
673        SlackActionBlockElement::DatePicker(element)
674    }
675}
676
677#[skip_serializing_none]
678#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
679pub struct SlackBlockTimePickerElement {
680    pub action_id: SlackActionId,
681    pub initial_time: Option<String>,
682    pub confirm: Option<SlackBlockConfirmItem>,
683    pub focus_on_load: Option<bool>,
684    pub placeholder: Option<SlackBlockPlainTextOnly>,
685    pub timezone: Option<String>,
686}
687
688impl From<SlackBlockTimePickerElement> for SlackSectionBlockElement {
689    fn from(element: SlackBlockTimePickerElement) -> Self {
690        SlackSectionBlockElement::TimePicker(element)
691    }
692}
693
694impl From<SlackBlockTimePickerElement> for SlackInputBlockElement {
695    fn from(element: SlackBlockTimePickerElement) -> Self {
696        SlackInputBlockElement::TimePicker(element)
697    }
698}
699
700impl From<SlackBlockTimePickerElement> for SlackActionBlockElement {
701    fn from(element: SlackBlockTimePickerElement) -> Self {
702        SlackActionBlockElement::TimePicker(element)
703    }
704}
705
706#[skip_serializing_none]
707#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
708pub struct SlackBlockDateTimePickerElement {
709    pub action_id: SlackActionId,
710    pub initial_date_time: Option<SlackDateTime>,
711    pub confirm: Option<SlackBlockConfirmItem>,
712    pub focus_on_load: Option<bool>,
713}
714
715impl From<SlackBlockDateTimePickerElement> for SlackInputBlockElement {
716    fn from(element: SlackBlockDateTimePickerElement) -> Self {
717        SlackInputBlockElement::DateTimePicker(element)
718    }
719}
720
721impl From<SlackBlockDateTimePickerElement> for SlackActionBlockElement {
722    fn from(element: SlackBlockDateTimePickerElement) -> Self {
723        SlackActionBlockElement::DateTimePicker(element)
724    }
725}
726
727#[skip_serializing_none]
728#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
729pub struct SlackBlockPlainTextInputElement {
730    pub action_id: SlackActionId,
731    pub placeholder: Option<SlackBlockPlainTextOnly>,
732    pub initial_value: Option<String>,
733    pub multiline: Option<bool>,
734    pub min_length: Option<u64>,
735    pub max_length: Option<u64>,
736    pub focus_on_load: Option<bool>,
737}
738
739impl From<SlackBlockPlainTextInputElement> for SlackSectionBlockElement {
740    fn from(element: SlackBlockPlainTextInputElement) -> Self {
741        SlackSectionBlockElement::PlainTextInput(element)
742    }
743}
744
745impl From<SlackBlockPlainTextInputElement> for SlackInputBlockElement {
746    fn from(element: SlackBlockPlainTextInputElement) -> Self {
747        SlackInputBlockElement::PlainTextInput(element)
748    }
749}
750
751impl From<SlackBlockPlainTextInputElement> for SlackActionBlockElement {
752    fn from(element: SlackBlockPlainTextInputElement) -> Self {
753        SlackActionBlockElement::PlainTextInput(element)
754    }
755}
756
757#[skip_serializing_none]
758#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
759pub struct SlackBlockNumberInputElement {
760    pub action_id: SlackActionId,
761    pub is_decimal_allowed: bool,
762    pub focus_on_load: Option<bool>,
763    pub placeholder: Option<SlackBlockPlainTextOnly>,
764    pub initial_value: Option<String>,
765    pub min_value: Option<String>,
766    pub max_value: Option<String>,
767}
768
769impl From<SlackBlockNumberInputElement> for SlackSectionBlockElement {
770    fn from(element: SlackBlockNumberInputElement) -> Self {
771        SlackSectionBlockElement::NumberInput(element)
772    }
773}
774
775impl From<SlackBlockNumberInputElement> for SlackInputBlockElement {
776    fn from(element: SlackBlockNumberInputElement) -> Self {
777        SlackInputBlockElement::NumberInput(element)
778    }
779}
780
781impl From<SlackBlockNumberInputElement> for SlackActionBlockElement {
782    fn from(element: SlackBlockNumberInputElement) -> Self {
783        SlackActionBlockElement::NumberInput(element)
784    }
785}
786
787#[skip_serializing_none]
788#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
789pub struct SlackBlockUrlInputElement {
790    pub action_id: SlackActionId,
791    pub placeholder: Option<SlackBlockPlainTextOnly>,
792    pub initial_value: Option<String>,
793}
794
795impl From<SlackBlockUrlInputElement> for SlackSectionBlockElement {
796    fn from(element: SlackBlockUrlInputElement) -> Self {
797        SlackSectionBlockElement::UrlInput(element)
798    }
799}
800
801impl From<SlackBlockUrlInputElement> for SlackInputBlockElement {
802    fn from(element: SlackBlockUrlInputElement) -> Self {
803        SlackInputBlockElement::UrlInput(element)
804    }
805}
806
807impl From<SlackBlockUrlInputElement> for SlackActionBlockElement {
808    fn from(element: SlackBlockUrlInputElement) -> Self {
809        SlackActionBlockElement::UrlInput(element)
810    }
811}
812
813#[skip_serializing_none]
814#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
815pub struct SlackBlockEmailInputElement {
816    pub action_id: SlackActionId,
817    pub focus_on_load: Option<bool>,
818    pub placeholder: Option<SlackBlockPlainTextOnly>,
819    pub initial_value: Option<EmailAddress>,
820}
821
822impl From<SlackBlockEmailInputElement> for SlackInputBlockElement {
823    fn from(element: SlackBlockEmailInputElement) -> Self {
824        SlackInputBlockElement::EmailInput(element)
825    }
826}
827
828#[skip_serializing_none]
829#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
830pub struct SlackBlockRadioButtonsElement {
831    pub action_id: SlackActionId,
832    pub options: Vec<SlackBlockChoiceItem<SlackBlockText>>,
833    pub initial_option: Option<SlackBlockChoiceItem<SlackBlockText>>,
834    pub confirm: Option<SlackBlockConfirmItem>,
835    pub focus_on_load: Option<bool>,
836}
837
838impl From<SlackBlockRadioButtonsElement> for SlackSectionBlockElement {
839    fn from(element: SlackBlockRadioButtonsElement) -> Self {
840        SlackSectionBlockElement::RadioButtons(element)
841    }
842}
843
844impl From<SlackBlockRadioButtonsElement> for SlackInputBlockElement {
845    fn from(element: SlackBlockRadioButtonsElement) -> Self {
846        SlackInputBlockElement::RadioButtons(element)
847    }
848}
849
850impl From<SlackBlockRadioButtonsElement> for SlackActionBlockElement {
851    fn from(element: SlackBlockRadioButtonsElement) -> Self {
852        SlackActionBlockElement::RadioButtons(element)
853    }
854}
855
856#[skip_serializing_none]
857#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
858pub struct SlackBlockCheckboxesElement {
859    pub action_id: SlackActionId,
860    pub options: Vec<SlackBlockChoiceItem<SlackBlockText>>,
861    pub initial_options: Option<Vec<SlackBlockChoiceItem<SlackBlockText>>>,
862    pub confirm: Option<SlackBlockConfirmItem>,
863    pub focus_on_load: Option<bool>,
864}
865
866impl From<SlackBlockCheckboxesElement> for SlackSectionBlockElement {
867    fn from(element: SlackBlockCheckboxesElement) -> Self {
868        SlackSectionBlockElement::Checkboxes(element)
869    }
870}
871
872impl From<SlackBlockCheckboxesElement> for SlackInputBlockElement {
873    fn from(element: SlackBlockCheckboxesElement) -> Self {
874        SlackInputBlockElement::Checkboxes(element)
875    }
876}
877
878impl From<SlackBlockCheckboxesElement> for SlackActionBlockElement {
879    fn from(element: SlackBlockCheckboxesElement) -> Self {
880        SlackActionBlockElement::Checkboxes(element)
881    }
882}
883
884/**
885 * 'plain_text' type of https://api.slack.com/reference/block-kit/composition-objects#text
886 */
887#[skip_serializing_none]
888#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
889pub struct SlackBlockPlainText {
890    pub text: String,
891    pub emoji: Option<bool>,
892}
893
894/**
895 * 'mrkdwn' type of https://api.slack.com/reference/block-kit/composition-objects#text
896 */
897#[skip_serializing_none]
898#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
899pub struct SlackBlockMarkDownText {
900    pub text: String,
901    pub verbatim: Option<bool>,
902}
903
904/**
905 * https://api.slack.com/reference/block-kit/composition-objects#text
906 */
907#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
908#[serde(tag = "type")]
909pub enum SlackBlockText {
910    #[serde(rename = "plain_text")]
911    Plain(SlackBlockPlainText),
912    #[serde(rename = "mrkdwn")]
913    MarkDown(SlackBlockMarkDownText),
914}
915
916#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
917#[serde(tag = "type", rename = "plain_text")]
918pub struct SlackBlockPlainTextOnly {
919    #[serde(flatten)]
920    value: SlackBlockPlainText,
921}
922
923impl SlackBlockPlainText {
924    pub fn as_block_text(&self) -> SlackBlockText {
925        SlackBlockText::Plain(self.clone())
926    }
927}
928
929impl From<String> for SlackBlockPlainText {
930    fn from(value: String) -> Self {
931        SlackBlockPlainText::new(value)
932    }
933}
934
935impl From<&str> for SlackBlockPlainText {
936    fn from(value: &str) -> Self {
937        SlackBlockPlainText::new(String::from(value))
938    }
939}
940
941impl SlackBlockMarkDownText {
942    pub fn as_block_text(&self) -> SlackBlockText {
943        SlackBlockText::MarkDown(self.clone())
944    }
945}
946
947impl From<String> for SlackBlockMarkDownText {
948    fn from(value: String) -> Self {
949        SlackBlockMarkDownText::new(value)
950    }
951}
952
953impl From<&str> for SlackBlockMarkDownText {
954    fn from(value: &str) -> Self {
955        SlackBlockMarkDownText::new(String::from(value))
956    }
957}
958
959impl From<SlackBlockPlainText> for SlackBlockPlainTextOnly {
960    fn from(pt: SlackBlockPlainText) -> Self {
961        SlackBlockPlainTextOnly { value: pt }
962    }
963}
964
965impl From<SlackBlockPlainText> for SlackBlockText {
966    fn from(text: SlackBlockPlainText) -> Self {
967        SlackBlockText::Plain(text)
968    }
969}
970
971impl From<SlackBlockMarkDownText> for SlackBlockText {
972    fn from(text: SlackBlockMarkDownText) -> Self {
973        SlackBlockText::MarkDown(text)
974    }
975}
976
977impl From<SlackBlockPlainText> for SlackContextBlockElement {
978    fn from(text: SlackBlockPlainText) -> Self {
979        SlackContextBlockElement::Plain(text)
980    }
981}
982
983impl From<SlackBlockMarkDownText> for SlackContextBlockElement {
984    fn from(text: SlackBlockMarkDownText) -> Self {
985        SlackContextBlockElement::MarkDown(text)
986    }
987}
988
989impl From<SlackBlockPlainTextOnly> for SlackBlockText {
990    fn from(text: SlackBlockPlainTextOnly) -> Self {
991        SlackBlockText::Plain(text.value)
992    }
993}
994
995impl From<String> for SlackBlockPlainTextOnly {
996    fn from(value: String) -> Self {
997        SlackBlockPlainTextOnly {
998            value: value.into(),
999        }
1000    }
1001}
1002
1003impl From<&str> for SlackBlockPlainTextOnly {
1004    fn from(value: &str) -> Self {
1005        SlackBlockPlainTextOnly {
1006            value: value.into(),
1007        }
1008    }
1009}
1010
1011/**
1012 * https://api.slack.com/reference/block-kit/blocks#video
1013 */
1014#[skip_serializing_none]
1015#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
1016pub struct SlackVideoBlock {
1017    pub alt_text: String,
1018    pub author_name: Option<String>,
1019    pub block_id: Option<SlackBlockId>,
1020    pub description: Option<SlackBlockPlainTextOnly>,
1021    pub provider_icon_url: Option<Url>,
1022    pub provider_name: Option<String>,
1023    pub title: SlackBlockPlainTextOnly,
1024    pub title_url: Option<Url>,
1025    pub thumbnail_url: Url,
1026    pub video_url: Url,
1027}
1028
1029impl From<SlackVideoBlock> for SlackBlock {
1030    fn from(block: SlackVideoBlock) -> Self {
1031        SlackBlock::Video(block)
1032    }
1033}
1034
1035/**
1036 * https://api.slack.com/reference/block-kit/blocks#markdown
1037 */
1038#[skip_serializing_none]
1039#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
1040pub struct SlackMarkdownBlock {
1041    pub block_id: Option<SlackBlockId>,
1042    pub text: String,
1043}
1044
1045impl From<SlackMarkdownBlock> for SlackBlock {
1046    fn from(block: SlackMarkdownBlock) -> Self {
1047        SlackBlock::Markdown(block)
1048    }
1049}
1050
1051#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
1052#[serde(untagged)]
1053pub enum SlackImageUrlOrFile {
1054    ImageUrl { image_url: Url },
1055    SlackFile { slack_file: SlackFileIdOrUrl },
1056}
1057
1058impl SlackImageUrlOrFile {
1059    pub fn image_url(&self) -> Option<&Url> {
1060        match self {
1061            SlackImageUrlOrFile::ImageUrl { image_url } => Some(image_url),
1062            SlackImageUrlOrFile::SlackFile { slack_file } => match slack_file {
1063                SlackFileIdOrUrl::Url { url } => Some(url),
1064                _ => None,
1065            },
1066        }
1067    }
1068}
1069
1070impl From<Url> for SlackImageUrlOrFile {
1071    fn from(value: Url) -> Self {
1072        SlackImageUrlOrFile::ImageUrl { image_url: value }
1073    }
1074}
1075
1076#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
1077#[serde(untagged)]
1078pub enum SlackFileIdOrUrl {
1079    Id { id: SlackFileId },
1080    Url { url: Url },
1081}
1082
1083impl From<SlackFileId> for SlackFileIdOrUrl {
1084    fn from(value: SlackFileId) -> Self {
1085        SlackFileIdOrUrl::Id { id: value }
1086    }
1087}
1088
1089#[cfg(test)]
1090mod test {
1091    use super::*;
1092    use crate::blocks::SlackHomeView;
1093
1094    #[test]
1095    fn test_slack_image_block_deserialize() -> Result<(), Box<dyn std::error::Error>> {
1096        let payload = include_str!("./fixtures/slack_image_blocks.json");
1097        let content: SlackMessageContent = serde_json::from_str(payload)?;
1098        let blocks = content.blocks.expect("Blocks should not be empty");
1099        match blocks.first() {
1100            Some(SlackBlock::Section(section)) => match &section.accessory {
1101                Some(SlackSectionBlockElement::Image(image)) => {
1102                    assert_eq!(image.alt_text, "alt text for image");
1103                    match &image.image_url_or_file {
1104                        SlackImageUrlOrFile::ImageUrl { image_url } => {
1105                            assert_eq!(image_url.as_str(), "https://s3-media3.fl.yelpcdn.com/bphoto/c7ed05m9lC2EmA3Aruue7A/o.jpg");
1106                        }
1107                        SlackImageUrlOrFile::SlackFile { slack_file } => {
1108                            panic!("Expected an image URL, not a Slack file: {:?}", slack_file);
1109                        }
1110                    }
1111                }
1112                _ => panic!("Expected a section block with an image accessory"),
1113            },
1114            _ => panic!("Expected a section block"),
1115        }
1116        Ok(())
1117    }
1118}