slack_rust/chat/
schedule_message.rs

1//! Schedules a message to be sent to a channel.  
2//! See: <https://api.slack.com/methods/chat.scheduleMessage>
3
4use crate::attachment::attachment::Attachment;
5use crate::block::blocks::Block;
6use crate::chat::message::Message;
7use crate::error::Error;
8use crate::http_client::{get_slack_url, ResponseMetadata, SlackWebAPIClient};
9use serde::{Deserialize, Serialize};
10use serde_with::skip_serializing_none;
11
12#[skip_serializing_none]
13#[derive(Deserialize, Serialize, Debug, Default, PartialEq)]
14pub struct ScheduledMessageRequest {
15    pub channel: String,
16    pub post_at: i32,
17    pub text: String,
18    pub as_user: Option<bool>,
19    pub attachments: Option<Vec<Attachment>>,
20    pub blocks: Option<Vec<Block>>,
21    pub link_names: Option<bool>,
22    pub parse: Option<String>,
23    pub reply_broadcast: Option<bool>,
24    pub thread_ts: Option<String>,
25    pub unfurl_links: Option<bool>,
26    pub unfurl_media: Option<bool>,
27}
28
29#[skip_serializing_none]
30#[derive(Deserialize, Serialize, Debug, Default, PartialEq)]
31pub struct ScheduledMessageResponse {
32    pub ok: bool,
33    pub error: Option<String>,
34    pub response_metadata: Option<ResponseMetadata>,
35    pub channel: Option<String>,
36    pub scheduled_message_id: Option<String>,
37    pub post_at: Option<String>,
38    pub message: Option<Message>,
39}
40
41/// Schedules a message to be sent to a channel.  
42/// See: <https://api.slack.com/methods/chat.scheduleMessage>
43pub async fn scheduled_message<T>(
44    client: &T,
45    param: &ScheduledMessageRequest,
46    bot_token: &str,
47) -> Result<ScheduledMessageResponse, Error>
48where
49    T: SlackWebAPIClient,
50{
51    let url = get_slack_url("chat.scheduleMessage");
52    let json = serde_json::to_string(&param)?;
53
54    client
55        .post_json(&url, &json, bot_token)
56        .await
57        .and_then(|result| {
58            serde_json::from_str::<ScheduledMessageResponse>(&result).map_err(Error::SerdeJsonError)
59        })
60}
61
62#[cfg(test)]
63mod test {
64    use super::*;
65    use crate::block::block_object::{TextBlockObject, TextBlockType};
66    use crate::block::block_section::SectionBlock;
67    use crate::http_client::MockSlackWebAPIClient;
68
69    #[test]
70    fn convert_request() {
71        let request = ScheduledMessageRequest {
72            channel: "C1234567890".to_string(),
73            post_at: 299876400,
74            text: "Hello world".to_string(),
75            as_user: Some(true),
76            attachments: Some(vec![Attachment {
77                pretext: Some("pre-hello".to_string()),
78                text: Some("text-world".to_string()),
79                ..Default::default()
80            }]),
81            blocks: Some(vec![Block::SectionBlock(SectionBlock {
82                text: Some(TextBlockObject {
83                    type_filed: TextBlockType::PlainText,
84                    text: "text".to_string(),
85                    ..Default::default()
86                }),
87                ..Default::default()
88            })]),
89            link_names: Some(true),
90            parse: Some("full".to_string()),
91            reply_broadcast: Some(true),
92            thread_ts: Some("1234567890.123456".to_string()),
93            unfurl_links: Some(true),
94            unfurl_media: Some(true),
95        };
96        let json = r##"{
97  "channel": "C1234567890",
98  "post_at": 299876400,
99  "text": "Hello world",
100  "as_user": true,
101  "attachments": [
102    {
103      "pretext": "pre-hello",
104      "text": "text-world"
105    }
106  ],
107  "blocks": [
108    {
109      "type": "section",
110      "text": {
111        "type": "plain_text",
112        "text": "text"
113      }
114    }
115  ],
116  "link_names": true,
117  "parse": "full",
118  "reply_broadcast": true,
119  "thread_ts": "1234567890.123456",
120  "unfurl_links": true,
121  "unfurl_media": true
122}"##;
123
124        let j = serde_json::to_string_pretty(&request).unwrap();
125        assert_eq!(json, j);
126
127        let s = serde_json::from_str::<ScheduledMessageRequest>(json).unwrap();
128        assert_eq!(request, s);
129    }
130
131    #[test]
132    fn convert_response() {
133        let response = ScheduledMessageResponse {
134            ok: true,
135            channel: Some("C1H9RESGL".to_string()),
136            scheduled_message_id: Some("Q1298393284".to_string()),
137            post_at: Some("1562180400".to_string()),
138            message: Some(Message {
139                bot_id: Some("B19LU7CSY".to_string()),
140                type_file: Some("delayed_message".to_string()),
141                text: Some("Here's a message for you in the future".to_string()),
142                user: Some("ecto1".to_string()),
143                attachments: Some(vec![Attachment {
144                    fallback: Some("This is an attachment's fallback".to_string()),
145                    id: Some(1),
146                    text: Some("This is an attachment".to_string()),
147                    ..Default::default()
148                }]),
149                subtype: Some("bot_message".to_string()),
150                ..Default::default()
151            }),
152            ..Default::default()
153        };
154        let json = r##"{
155  "ok": true,
156  "channel": "C1H9RESGL",
157  "scheduled_message_id": "Q1298393284",
158  "post_at": "1562180400",
159  "message": {
160    "bot_id": "B19LU7CSY",
161    "type": "delayed_message",
162    "text": "Here's a message for you in the future",
163    "user": "ecto1",
164    "attachments": [
165      {
166        "fallback": "This is an attachment's fallback",
167        "id": 1,
168        "text": "This is an attachment"
169      }
170    ],
171    "subtype": "bot_message"
172  }
173}"##;
174
175        let j = serde_json::to_string_pretty(&response).unwrap();
176        assert_eq!(json, j);
177
178        let s = serde_json::from_str::<ScheduledMessageResponse>(json).unwrap();
179        assert_eq!(response, s);
180    }
181
182    #[async_std::test]
183    async fn test_scheduled_message() {
184        let param = ScheduledMessageRequest {
185            channel: "C1234567890".to_string(),
186            post_at: 299876400,
187            text: "Hello world".to_string(),
188            as_user: Some(true),
189            attachments: Some(vec![Attachment {
190                pretext: Some("pre-hello".to_string()),
191                text: Some("text-world".to_string()),
192                ..Default::default()
193            }]),
194            blocks: Some(vec![Block::SectionBlock(SectionBlock {
195                text: Some(TextBlockObject {
196                    type_filed: TextBlockType::PlainText,
197                    text: "text".to_string(),
198                    ..Default::default()
199                }),
200                ..Default::default()
201            })]),
202            link_names: Some(true),
203            parse: Some("full".to_string()),
204            reply_broadcast: Some(true),
205            thread_ts: Some("1234567890.123456".to_string()),
206            unfurl_links: Some(true),
207            unfurl_media: Some(true),
208        };
209
210        let mut mock = MockSlackWebAPIClient::new();
211        mock.expect_post_json().returning(|_, _, _| {
212            Ok(r##"{
213  "ok": true,
214  "channel": "C1H9RESGL",
215  "scheduled_message_id": "Q1298393284",
216  "post_at": "1562180400",
217  "message": {
218    "bot_id": "B19LU7CSY",
219    "type": "delayed_message",
220    "text": "Here's a message for you in the future",
221    "user": "ecto1",
222    "attachments": [
223      {
224        "fallback": "This is an attachment's fallback",
225        "id": 1,
226        "text": "This is an attachment"
227      }
228    ],
229    "subtype": "bot_message"
230  }
231}"##
232            .to_string())
233        });
234
235        let response = scheduled_message(&mock, &param, &"test_token".to_string())
236            .await
237            .unwrap();
238        let expect = ScheduledMessageResponse {
239            ok: true,
240            channel: Some("C1H9RESGL".to_string()),
241            scheduled_message_id: Some("Q1298393284".to_string()),
242            post_at: Some("1562180400".to_string()),
243            message: Some(Message {
244                bot_id: Some("B19LU7CSY".to_string()),
245                type_file: Some("delayed_message".to_string()),
246                text: Some("Here's a message for you in the future".to_string()),
247                user: Some("ecto1".to_string()),
248                attachments: Some(vec![Attachment {
249                    fallback: Some("This is an attachment's fallback".to_string()),
250                    id: Some(1),
251                    text: Some("This is an attachment".to_string()),
252                    ..Default::default()
253                }]),
254                subtype: Some("bot_message".to_string()),
255                ..Default::default()
256            }),
257            ..Default::default()
258        };
259
260        assert_eq!(expect, response);
261    }
262}