slack_hook/
payload.rs

1use crate::{Attachment, Result, SlackText};
2use reqwest::Url;
3use serde::{Serialize, Serializer};
4
5/// Payload to send to slack
6/// <https://api.slack.com/incoming-webhooks>
7/// <https://api.slack.com/methods/chat.postMessage>
8#[derive(Serialize, Debug, Default)]
9pub struct Payload {
10    /// text to send
11    /// despite `text` stated as required, it does not seem to be
12    #[serde(skip_serializing_if = "Option::is_none")]
13    pub text: Option<SlackText>,
14    /// channel to send payload to
15    /// note: if not provided, this will default to channel
16    /// setup in slack
17    #[serde(skip_serializing_if = "Option::is_none")]
18    pub channel: Option<String>,
19    /// username override
20    #[serde(skip_serializing_if = "Option::is_none")]
21    pub username: Option<String>,
22    /// specific url for icon
23    #[serde(skip_serializing_if = "Option::is_none")]
24    pub icon_url: Option<Url>,
25    /// emoji for icon
26    /// <https://api.slack.com/methods/emoji.list>
27    #[serde(skip_serializing_if = "Option::is_none")]
28    pub icon_emoji: Option<String>,
29    /// attachments to send
30    #[serde(skip_serializing_if = "Option::is_none")]
31    pub attachments: Option<Vec<Attachment>>,
32    /// whether slack will try to fetch links and create an attachment
33    /// <https://api.slack.com/docs/unfurling>
34    #[serde(skip_serializing_if = "Option::is_none")]
35    pub unfurl_links: Option<bool>,
36    /// Pass false to disable unfurling of media content
37    #[serde(skip_serializing_if = "Option::is_none")]
38    pub unfurl_media: Option<bool>,
39    /// find and link channel names and usernames
40    #[serde(skip_serializing_if = "Option::is_none")]
41    pub link_names: Option<u8>,
42    /// Change how messages are treated.
43    #[serde(skip_serializing_if = "Option::is_none")]
44    pub parse: Option<Parse>,
45}
46
47/// Change how messages are treated.
48#[derive(Debug)]
49pub enum Parse {
50    /// Full
51    Full,
52    /// None
53    None,
54}
55
56impl Serialize for Parse {
57    fn serialize<S>(&self, serializer: S) -> ::std::result::Result<S::Ok, S::Error>
58    where
59        S: Serializer,
60    {
61        let st = match *self {
62            Parse::Full => "full",
63            Parse::None => "none",
64        };
65        serializer.serialize_str(st)
66    }
67}
68/// `PayloadBuilder` is used to build a `Payload`
69#[derive(Debug)]
70#[must_use]
71pub struct PayloadBuilder {
72    inner: Result<Payload>,
73}
74
75impl Default for PayloadBuilder {
76    fn default() -> PayloadBuilder {
77        PayloadBuilder {
78            inner: Ok(Default::default()),
79        }
80    }
81}
82
83impl PayloadBuilder {
84    /// Make a new `PayloadBuilder`
85    pub fn new() -> Self {
86        Default::default()
87    }
88
89    /// Set the text
90    pub fn text<S: Into<SlackText>>(mut self, text: S) -> Self {
91        if let Ok(inner) = &mut self.inner {
92            inner.text = Some(text.into());
93        }
94        self
95    }
96
97    /// Set the channel
98    pub fn channel<S: Into<String>>(mut self, channel: S) -> Self {
99        if let Ok(inner) = &mut self.inner {
100            inner.channel = Some(channel.into());
101        }
102        self
103    }
104
105    /// Set the username
106    pub fn username<S: Into<String>>(mut self, username: S) -> Self {
107        if let Ok(inner) = &mut self.inner {
108            inner.username = Some(username.into());
109        }
110        self
111    }
112
113    /// Set the icon_emoji
114    pub fn icon_emoji<S: Into<String>>(mut self, icon_emoji: S) -> Self {
115        if let Ok(inner) = &mut self.inner {
116            inner.icon_emoji = Some(icon_emoji.into());
117        }
118        self
119    }
120
121    url_builder_fn! {
122        /// Set the icon_url
123        icon_url, Self
124    }
125
126    /// Set the attachments
127    pub fn attachments(mut self, attachments: Vec<Attachment>) -> Self {
128        if let Ok(inner) = &mut self.inner {
129            inner.attachments = Some(attachments);
130        }
131        self
132    }
133
134    /// whether slack will try to fetch links and create an attachment
135    /// <https://api.slack.com/docs/unfurling>
136    pub fn unfurl_links(mut self, b: bool) -> Self {
137        if let Ok(inner) = &mut self.inner {
138            inner.unfurl_links = Some(b);
139        }
140        self
141    }
142
143    /// Pass false to disable unfurling of media content
144    pub fn unfurl_media(mut self, b: bool) -> Self {
145        if let Ok(inner) = &mut self.inner {
146            inner.unfurl_media = Some(b);
147        }
148        self
149    }
150
151    /// Find and link channel names and usernames.
152    // NOTE: The Slack API doesn't seem to actually require setting `link_names` to 1, any value
153    // seems to work. However, to be faithful to their spec we will stick to 0 and 1
154    pub fn link_names(mut self, b: bool) -> Self {
155        if let Ok(inner) = &mut self.inner {
156            inner.link_names = Some(u8::from(b));
157        }
158        self
159    }
160
161    /// Change how messages are treated.
162    pub fn parse(mut self, p: Parse) -> Self {
163        if let Ok(inner) = &mut self.inner {
164            inner.parse = Some(p);
165        }
166        self
167    }
168
169    /// Attempt to build the `Payload`
170    pub fn build(self) -> Result<Payload> {
171        self.inner
172    }
173}