1use 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(¶m)?;
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, ¶m, &"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}