slack_rust/chat/
post_ephemeral.rs

1//! Sends an ephemeral message to a user in a channel.  
2//! See: <https://api.slack.com/methods/chat.postEphemeral>
3
4use crate::attachment::attachment::Attachment;
5use crate::block::blocks::Block;
6use crate::error::Error;
7use crate::http_client::{get_slack_url, ResponseMetadata, SlackWebAPIClient};
8use serde::{Deserialize, Serialize};
9use serde_with::skip_serializing_none;
10
11#[skip_serializing_none]
12#[derive(Deserialize, Serialize, Debug, Default, PartialEq)]
13pub struct PostEphemeralRequest {
14    pub channel: String,
15    pub text: String,
16    pub user: String,
17    pub as_user: Option<bool>,
18    pub attachments: Option<Vec<Attachment>>,
19    pub blocks: Option<Vec<Block>>,
20    pub icon_emoji: Option<String>,
21    pub icon_url: Option<String>,
22    pub link_names: Option<bool>,
23    pub parse: Option<String>,
24    pub thread_ts: Option<String>,
25    pub username: Option<String>,
26}
27
28#[skip_serializing_none]
29#[derive(Deserialize, Serialize, Debug, Default, PartialEq)]
30pub struct PostEphemeralResponse {
31    pub ok: bool,
32    pub error: Option<String>,
33    pub response_metadata: Option<ResponseMetadata>,
34    pub message_ts: Option<String>,
35}
36
37pub async fn post_ephemeral<T>(
38    client: &T,
39    param: &PostEphemeralRequest,
40    bot_token: &str,
41) -> Result<PostEphemeralResponse, Error>
42where
43    T: SlackWebAPIClient,
44{
45    let url = get_slack_url("chat.postEphemeral");
46    let json = serde_json::to_string(&param)?;
47
48    client
49        .post_json(&url, &json, bot_token)
50        .await
51        .and_then(|result| {
52            serde_json::from_str::<PostEphemeralResponse>(&result).map_err(Error::SerdeJsonError)
53        })
54}
55
56#[cfg(test)]
57mod test {
58    use super::*;
59    use crate::block::block_object::{TextBlockObject, TextBlockType};
60    use crate::block::block_section::SectionBlock;
61    use crate::http_client::MockSlackWebAPIClient;
62
63    #[test]
64    fn convert_request() {
65        let request = PostEphemeralRequest {
66            channel: "C1234567890".to_string(),
67            text: "Hello world".to_string(),
68            user: "U0BPQUNTA".to_string(),
69            as_user: Some(true),
70            attachments: Some(vec![Attachment {
71                pretext: Some("pre-hello".to_string()),
72                text: Some("text-world".to_string()),
73                ..Default::default()
74            }]),
75            blocks: Some(vec![Block::SectionBlock(SectionBlock {
76                text: Some(TextBlockObject {
77                    type_filed: TextBlockType::PlainText,
78                    text: "text".to_string(),
79                    ..Default::default()
80                }),
81                ..Default::default()
82            })]),
83            icon_emoji: Some(":chart_with_upwards_trend:".to_string()),
84            icon_url: Some("http://lorempixel.com/48/48".to_string()),
85            link_names: Some(true),
86            parse: Some("full".to_string()),
87            thread_ts: Some("1234567890.123456".to_string()),
88            username: Some("My Bot".to_string()),
89        };
90        let json = r##"{
91  "channel": "C1234567890",
92  "text": "Hello world",
93  "user": "U0BPQUNTA",
94  "as_user": true,
95  "attachments": [
96    {
97      "pretext": "pre-hello",
98      "text": "text-world"
99    }
100  ],
101  "blocks": [
102    {
103      "type": "section",
104      "text": {
105        "type": "plain_text",
106        "text": "text"
107      }
108    }
109  ],
110  "icon_emoji": ":chart_with_upwards_trend:",
111  "icon_url": "http://lorempixel.com/48/48",
112  "link_names": true,
113  "parse": "full",
114  "thread_ts": "1234567890.123456",
115  "username": "My Bot"
116}"##;
117
118        let j = serde_json::to_string_pretty(&request).unwrap();
119        assert_eq!(json, j);
120
121        let s = serde_json::from_str::<PostEphemeralRequest>(json).unwrap();
122        assert_eq!(request, s);
123    }
124
125    #[test]
126    fn convert_response() {
127        let response = PostEphemeralResponse {
128            ok: true,
129            message_ts: Some("1502210682.580145".to_string()),
130            ..Default::default()
131        };
132        let json = r##"{
133  "ok": true,
134  "message_ts": "1502210682.580145"
135}"##;
136
137        let j = serde_json::to_string_pretty(&response).unwrap();
138        assert_eq!(json, j);
139
140        let s = serde_json::from_str::<PostEphemeralResponse>(json).unwrap();
141        assert_eq!(response, s);
142    }
143    #[async_std::test]
144    async fn test_post_ephemeral() {
145        let param = PostEphemeralRequest {
146            channel: "C1234567890".to_string(),
147            text: "Hello world".to_string(),
148            user: "U0BPQUNTA".to_string(),
149            as_user: Some(true),
150            attachments: Some(vec![Attachment {
151                pretext: Some("pre-hello".to_string()),
152                text: Some("text-world".to_string()),
153                ..Default::default()
154            }]),
155            blocks: Some(vec![Block::SectionBlock(SectionBlock {
156                text: Some(TextBlockObject {
157                    type_filed: TextBlockType::PlainText,
158                    text: "text".to_string(),
159                    ..Default::default()
160                }),
161                ..Default::default()
162            })]),
163            icon_emoji: Some(":chart_with_upwards_trend:".to_string()),
164            icon_url: Some("http://lorempixel.com/48/48".to_string()),
165            link_names: Some(true),
166            parse: Some("full".to_string()),
167            thread_ts: Some("1234567890.123456".to_string()),
168            username: Some("My Bot".to_string()),
169        };
170
171        let mut mock = MockSlackWebAPIClient::new();
172        mock.expect_post_json().returning(|_, _, _| {
173            Ok(r##"{
174  "ok": true,
175  "message_ts": "1502210682.580145"
176}"##
177            .to_string())
178        });
179
180        let response = post_ephemeral(&mock, &param, &"test_token".to_string())
181            .await
182            .unwrap();
183        let expect = PostEphemeralResponse {
184            ok: true,
185            message_ts: Some("1502210682.580145".to_string()),
186            ..Default::default()
187        };
188
189        assert_eq!(expect, response);
190    }
191}