Skip to main content

slack_web_api/blocks/
attachment.rs

1use serde::{Deserialize, Serialize};
2
3use super::block::Block;
4
5/// The `ts` of an attachment. Sent as a number, but returned as a string (e.g. `"1503435956.000247"`) in places such as message unfurls.
6#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7#[serde(untagged)]
8pub enum AttachmentTs {
9    Number(serde_json::Number),
10    String(String),
11}
12
13/// A legacy secondary message attachment (can also hold `blocks`). <https://docs.slack.dev/legacy/legacy-messaging/legacy-secondary-message-attachments>
14#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
15pub struct Attachment {
16    #[serde(skip_serializing_if = "Option::is_none")]
17    pub id: Option<i64>,
18    #[serde(skip_serializing_if = "Option::is_none")]
19    pub fallback: Option<String>,
20    #[serde(skip_serializing_if = "Option::is_none")]
21    pub color: Option<String>,
22    #[serde(skip_serializing_if = "Option::is_none")]
23    pub pretext: Option<String>,
24    #[serde(skip_serializing_if = "Option::is_none")]
25    pub author_name: Option<String>,
26    #[serde(skip_serializing_if = "Option::is_none")]
27    pub author_link: Option<String>,
28    #[serde(skip_serializing_if = "Option::is_none")]
29    pub author_icon: Option<String>,
30    #[serde(skip_serializing_if = "Option::is_none")]
31    pub title: Option<String>,
32    #[serde(skip_serializing_if = "Option::is_none")]
33    pub title_link: Option<String>,
34    #[serde(skip_serializing_if = "Option::is_none")]
35    pub text: Option<String>,
36    #[serde(default, skip_serializing_if = "Vec::is_empty")]
37    pub fields: Vec<AttachmentField>,
38    #[serde(skip_serializing_if = "Option::is_none")]
39    pub image_url: Option<String>,
40    #[serde(skip_serializing_if = "Option::is_none")]
41    pub thumb_url: Option<String>,
42    #[serde(skip_serializing_if = "Option::is_none")]
43    pub thumb_width: Option<u32>,
44    #[serde(skip_serializing_if = "Option::is_none")]
45    pub thumb_height: Option<u32>,
46    #[serde(skip_serializing_if = "Option::is_none")]
47    pub service_name: Option<String>,
48    #[serde(skip_serializing_if = "Option::is_none")]
49    pub footer: Option<String>,
50    #[serde(skip_serializing_if = "Option::is_none")]
51    pub footer_icon: Option<String>,
52    #[serde(skip_serializing_if = "Option::is_none")]
53    pub ts: Option<AttachmentTs>,
54    #[serde(default, skip_serializing_if = "Vec::is_empty")]
55    pub mrkdwn_in: Vec<String>,
56    #[serde(default, skip_serializing_if = "Vec::is_empty")]
57    pub blocks: Vec<Block>,
58}
59
60impl Attachment {
61    pub fn new() -> Self {
62        Self::default()
63    }
64
65    pub fn id(mut self, id: i64) -> Self {
66        self.id = Some(id);
67        self
68    }
69
70    pub fn fallback(mut self, fallback: impl Into<String>) -> Self {
71        self.fallback = Some(fallback.into());
72        self
73    }
74
75    pub fn color(mut self, color: impl Into<String>) -> Self {
76        self.color = Some(color.into());
77        self
78    }
79
80    pub fn pretext(mut self, pretext: impl Into<String>) -> Self {
81        self.pretext = Some(pretext.into());
82        self
83    }
84
85    pub fn author_name(mut self, author_name: impl Into<String>) -> Self {
86        self.author_name = Some(author_name.into());
87        self
88    }
89
90    pub fn author_link(mut self, author_link: impl Into<String>) -> Self {
91        self.author_link = Some(author_link.into());
92        self
93    }
94
95    pub fn author_icon(mut self, author_icon: impl Into<String>) -> Self {
96        self.author_icon = Some(author_icon.into());
97        self
98    }
99
100    pub fn title(mut self, title: impl Into<String>) -> Self {
101        self.title = Some(title.into());
102        self
103    }
104
105    pub fn title_link(mut self, title_link: impl Into<String>) -> Self {
106        self.title_link = Some(title_link.into());
107        self
108    }
109
110    pub fn text(mut self, text: impl Into<String>) -> Self {
111        self.text = Some(text.into());
112        self
113    }
114
115    pub fn fields(mut self, fields: Vec<AttachmentField>) -> Self {
116        self.fields = fields;
117        self
118    }
119
120    pub fn image_url(mut self, image_url: impl Into<String>) -> Self {
121        self.image_url = Some(image_url.into());
122        self
123    }
124
125    pub fn thumb_url(mut self, thumb_url: impl Into<String>) -> Self {
126        self.thumb_url = Some(thumb_url.into());
127        self
128    }
129
130    pub fn thumb_width(mut self, thumb_width: u32) -> Self {
131        self.thumb_width = Some(thumb_width);
132        self
133    }
134
135    pub fn thumb_height(mut self, thumb_height: u32) -> Self {
136        self.thumb_height = Some(thumb_height);
137        self
138    }
139
140    pub fn service_name(mut self, service_name: impl Into<String>) -> Self {
141        self.service_name = Some(service_name.into());
142        self
143    }
144
145    pub fn footer(mut self, footer: impl Into<String>) -> Self {
146        self.footer = Some(footer.into());
147        self
148    }
149
150    pub fn footer_icon(mut self, footer_icon: impl Into<String>) -> Self {
151        self.footer_icon = Some(footer_icon.into());
152        self
153    }
154
155    pub fn ts(mut self, ts: AttachmentTs) -> Self {
156        self.ts = Some(ts);
157        self
158    }
159
160    pub fn mrkdwn_in(mut self, mrkdwn_in: Vec<String>) -> Self {
161        self.mrkdwn_in = mrkdwn_in;
162        self
163    }
164
165    pub fn blocks(mut self, blocks: Vec<Block>) -> Self {
166        self.blocks = blocks;
167        self
168    }
169}
170
171/// A field shown in a table inside an attachment. <https://docs.slack.dev/legacy/legacy-messaging/legacy-secondary-message-attachments>
172#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
173pub struct AttachmentField {
174    pub title: String,
175    pub value: String,
176    #[serde(skip_serializing_if = "Option::is_none")]
177    pub short: Option<bool>,
178}
179
180impl AttachmentField {
181    pub fn new(title: impl Into<String>, value: impl Into<String>) -> Self {
182        Self {
183            title: title.into(),
184            value: value.into(),
185            short: None,
186        }
187    }
188
189    pub fn short(mut self, short: bool) -> Self {
190        self.short = Some(short);
191        self
192    }
193}