slack_morphism/api/
chat.rs

1//!
2//! Support for Slack Chat API methods
3//!
4
5use rsb_derive::Builder;
6use rvstruct::*;
7use serde::{Deserialize, Serialize};
8use serde_with::skip_serializing_none;
9
10use crate::models::blocks::{SlackBlock, SlackBlockText};
11use crate::models::*;
12use crate::ratectl::*;
13use crate::scroller::*;
14use crate::SlackClientSession;
15use crate::{ClientResult, SlackClientHttpConnector};
16use futures::future::{BoxFuture, FutureExt};
17use lazy_static::lazy_static;
18use std::collections::HashMap;
19use url::Url;
20
21impl<'a, SCHC> SlackClientSession<'a, SCHC>
22where
23    SCHC: SlackClientHttpConnector + Send,
24{
25    ///
26    /// https://api.slack.com/methods/chat.delete
27    ///
28    pub async fn chat_delete(
29        &self,
30        req: &SlackApiChatDeleteRequest,
31    ) -> ClientResult<SlackApiChatDeleteResponse> {
32        self.http_session_api
33            .http_post("chat.delete", req, Some(&SLACK_TIER3_METHOD_CONFIG))
34            .await
35    }
36
37    ///
38    /// https://api.slack.com/methods/chat.deleteScheduledMessage
39    ///
40    pub async fn chat_delete_scheduled_message(
41        &self,
42        req: &SlackApiChatDeleteScheduledMessageRequest,
43    ) -> ClientResult<SlackApiChatDeleteScheduledMessageResponse> {
44        self.http_session_api
45            .http_post(
46                "chat.deleteScheduledMessage",
47                req,
48                Some(&SLACK_TIER3_METHOD_CONFIG),
49            )
50            .await
51    }
52
53    ///
54    /// https://api.slack.com/methods/chat.getPermalink
55    ///
56    pub async fn chat_get_permalink(
57        &self,
58        req: &SlackApiChatGetPermalinkRequest,
59    ) -> ClientResult<SlackApiChatGetPermalinkResponse> {
60        self.http_session_api
61            .http_get(
62                "chat.getPermalink",
63                &vec![
64                    ("channel", Some(&req.channel.value())),
65                    ("message_ts", Some(&req.message_ts.value())),
66                ],
67                Some(&CHAT_GET_PERMLINK_SPECIAL_LIMIT_RATE_CTL),
68            )
69            .await
70    }
71
72    ///
73    /// https://api.slack.com/methods/chat.postEphemeral
74    ///
75    pub async fn chat_post_ephemeral(
76        &self,
77        req: &SlackApiChatPostEphemeralRequest,
78    ) -> ClientResult<SlackApiChatPostEphemeralResponse> {
79        self.http_session_api
80            .http_post("chat.postEphemeral", req, Some(&SLACK_TIER4_METHOD_CONFIG))
81            .await
82    }
83
84    ///
85    /// https://api.slack.com/methods/chat.postMessage
86    ///
87    pub async fn chat_post_message(
88        &self,
89        req: &SlackApiChatPostMessageRequest,
90    ) -> ClientResult<SlackApiChatPostMessageResponse> {
91        self.http_session_api
92            .http_post(
93                "chat.postMessage",
94                req,
95                Some(&CHAT_POST_MESSAGE_SPECIAL_LIMIT_RATE_CTL),
96            )
97            .await
98    }
99
100    ///
101    /// https://api.slack.com/methods/chat.scheduleMessage
102    ///
103    pub async fn chat_schedule_message(
104        &self,
105        req: &SlackApiChatScheduleMessageRequest,
106    ) -> ClientResult<SlackApiChatScheduleMessageResponse> {
107        self.http_session_api
108            .http_post(
109                "chat.scheduleMessage",
110                req,
111                Some(&SLACK_TIER3_METHOD_CONFIG),
112            )
113            .await
114    }
115
116    ///
117    /// The old/legacy version of unfurl with channel/ts
118    /// https://api.slack.com/methods/chat.unfurl
119    ///
120    pub async fn chat_unfurl(
121        &self,
122        req: &SlackApiChatUnfurlRequest,
123    ) -> ClientResult<SlackApiChatUnfurlResponse> {
124        self.http_session_api
125            .http_post("chat.unfurl", req, Some(&SLACK_TIER3_METHOD_CONFIG))
126            .await
127    }
128
129    ///
130    /// The version for unfurl with source/unfurl_id
131    /// https://api.slack.com/methods/chat.unfurl
132    ///
133    pub async fn chat_unfurl_v2(
134        &self,
135        req: &SlackApiChatUnfurlRequestV2,
136    ) -> ClientResult<SlackApiChatUnfurlResponse> {
137        self.http_session_api
138            .http_post("chat.unfurl", req, Some(&SLACK_TIER3_METHOD_CONFIG))
139            .await
140    }
141
142    ///
143    /// The version for unfurl that accepts both channel/ts and source/unfurl_id
144    /// and can use slack blocks.
145    /// https://api.slack.com/methods/chat.unfurl
146    ///
147    pub async fn chat_unfurl_v3(
148        &self,
149        req: &SlackApiChatUnfurlRequestV3,
150    ) -> ClientResult<SlackApiChatUnfurlResponse> {
151        self.http_session_api
152            .http_post("chat.unfurl", req, Some(&SLACK_TIER3_METHOD_CONFIG))
153            .await
154    }
155
156    ///
157    /// https://api.slack.com/methods/chat.update
158    ///
159    pub async fn chat_update(
160        &self,
161        req: &SlackApiChatUpdateRequest,
162    ) -> ClientResult<SlackApiChatUpdateResponse> {
163        self.http_session_api
164            .http_post("chat.update", req, Some(&SLACK_TIER3_METHOD_CONFIG))
165            .await
166    }
167
168    ///
169    /// https://api.slack.com/methods/chat.scheduledMessages.list
170    ///
171    pub async fn chat_scheduled_messages_list(
172        &self,
173        req: &SlackApiChatScheduledMessagesListRequest,
174    ) -> ClientResult<SlackApiChatScheduledMessagesListResponse> {
175        self.http_session_api
176            .http_post(
177                "chat.scheduledMessages.list",
178                req,
179                Some(&SLACK_TIER3_METHOD_CONFIG),
180            )
181            .await
182    }
183}
184
185#[skip_serializing_none]
186#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
187pub struct SlackApiChatDeleteRequest {
188    pub channel: SlackChannelId,
189    pub ts: SlackTs,
190    pub as_user: Option<bool>,
191}
192
193#[skip_serializing_none]
194#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
195pub struct SlackApiChatDeleteResponse {
196    pub channel: SlackChannelId,
197    pub ts: SlackTs,
198}
199
200#[skip_serializing_none]
201#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
202pub struct SlackApiChatDeleteScheduledMessageRequest {
203    pub channel: SlackChannelId,
204    pub scheduled_message: SlackScheduledMid,
205    pub as_user: Option<bool>,
206}
207
208#[skip_serializing_none]
209#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
210pub struct SlackApiChatDeleteScheduledMessageResponse {}
211
212#[skip_serializing_none]
213#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
214pub struct SlackApiChatGetPermalinkRequest {
215    pub channel: SlackChannelId,
216    pub message_ts: SlackTs,
217}
218
219#[skip_serializing_none]
220#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
221pub struct SlackApiChatGetPermalinkResponse {
222    pub channel: SlackChannelId,
223    pub permalink: Url,
224}
225
226#[skip_serializing_none]
227#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
228pub struct SlackApiChatPostEphemeralRequest {
229    pub channel: SlackChannelId,
230    pub user: SlackUserId,
231    #[serde(flatten)]
232    pub content: SlackMessageContent,
233    pub as_user: Option<bool>,
234    pub icon_emoji: Option<String>,
235    pub icon_url: Option<String>,
236    pub link_names: Option<bool>,
237    pub parse: Option<String>,
238    pub thread_ts: Option<SlackTs>,
239    pub username: Option<String>,
240}
241
242#[skip_serializing_none]
243#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
244pub struct SlackApiChatPostEphemeralResponse {}
245
246#[skip_serializing_none]
247#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
248pub struct SlackApiChatPostMessageRequest {
249    pub channel: SlackChannelId,
250    #[serde(flatten)]
251    pub content: SlackMessageContent,
252    pub as_user: Option<bool>,
253    pub icon_emoji: Option<String>,
254    pub icon_url: Option<String>,
255    pub link_names: Option<bool>,
256    pub parse: Option<String>,
257    pub thread_ts: Option<SlackTs>,
258    pub username: Option<String>,
259    pub reply_broadcast: Option<bool>,
260    pub unfurl_links: Option<bool>,
261    pub unfurl_media: Option<bool>,
262}
263
264#[skip_serializing_none]
265#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
266pub struct SlackApiChatPostMessageResponse {
267    pub channel: SlackChannelId,
268    pub ts: SlackTs,
269    pub message: SlackMessage,
270}
271
272#[skip_serializing_none]
273#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
274pub struct SlackApiChatScheduleMessageRequest {
275    pub channel: SlackChannelId,
276    #[serde(flatten)]
277    pub content: SlackMessageContent,
278    pub post_at: SlackDateTime,
279    pub as_user: Option<bool>,
280    pub icon_emoji: Option<String>,
281    pub icon_url: Option<String>,
282    pub link_names: Option<bool>,
283    pub parse: Option<String>,
284    pub thread_ts: Option<SlackTs>,
285    pub username: Option<String>,
286    pub reply_broadcast: Option<bool>,
287    pub unfurl_links: Option<bool>,
288    pub unfurl_media: Option<bool>,
289}
290
291#[skip_serializing_none]
292#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
293pub struct SlackApiChatScheduleMessageResponse {
294    pub channel: SlackChannelId,
295    pub scheduled_message_id: SlackScheduledMid,
296    pub post_at: SlackDateTime,
297}
298
299#[skip_serializing_none]
300#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
301pub struct SlackApiChatUnfurlRequest {
302    pub channel: SlackChannelId,
303    pub ts: SlackTs,
304    pub unfurls: HashMap<String, SlackApiChatUnfurlMapItem>,
305    pub user_auth_message: Option<String>,
306    pub user_auth_required: Option<bool>,
307    pub user_auth_url: Option<Url>,
308}
309
310#[skip_serializing_none]
311#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
312pub struct SlackApiChatUnfurlRequestV2 {
313    pub source: SlackApiChatUnfurlSource,
314    pub unfurl_id: SlackUnfurlId,
315    pub unfurls: HashMap<String, SlackApiChatUnfurlMapItemV2>,
316    pub user_auth_message: Option<String>,
317    pub user_auth_required: Option<bool>,
318    pub user_auth_url: Option<Url>,
319}
320
321#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
322pub struct SlackChannelTs {
323    pub channel: SlackChannelId,
324    pub ts: SlackTs,
325}
326
327#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
328pub struct SlackUnfurlIdSource {
329    pub source: String,
330    pub unfurl_id: SlackUnfurlId,
331}
332
333#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
334#[serde(untagged)]
335pub enum SlackUnfurlRequestId {
336    ChannelTs(SlackChannelTs),
337    UnfurlIdSource(SlackUnfurlIdSource),
338}
339
340#[skip_serializing_none]
341#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
342pub struct SlackApiChatUnfurlRequestV3 {
343    #[serde(flatten)]
344    pub id: SlackUnfurlRequestId,
345    pub unfurls: HashMap<String, SlackApiChatUnfurlMapItemV2>,
346    pub user_auth_message: Option<String>,
347    pub user_auth_required: Option<bool>,
348    pub user_auth_url: Option<Url>,
349}
350
351#[skip_serializing_none]
352#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
353pub enum SlackApiChatUnfurlSource {
354    #[serde(rename = "composer")]
355    Composer,
356    #[serde(rename = "conversations_history")]
357    ConversationsHistory,
358}
359
360#[skip_serializing_none]
361#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
362pub struct SlackApiChatUnfurlMapItem {
363    pub text: String,
364}
365
366#[skip_serializing_none]
367#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
368pub struct SlackApiChatUnfurlMapItemV2 {
369    pub blocks: Vec<SlackBlock>,
370    pub preview: Option<SlackApiChatUnfurlPreview>,
371}
372
373#[skip_serializing_none]
374#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
375pub struct SlackApiChatUnfurlPreview {
376    pub title: SlackBlockText,
377    pub icon_url: Option<Url>,
378}
379
380#[skip_serializing_none]
381#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
382pub struct SlackApiChatUnfurlResponse {}
383
384#[skip_serializing_none]
385#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
386pub struct SlackApiChatUpdateRequest {
387    pub channel: SlackChannelId,
388    #[serde(flatten)]
389    pub content: SlackMessageContent,
390    pub ts: SlackTs,
391    pub as_user: Option<bool>,
392    pub link_names: Option<bool>,
393    pub parse: Option<String>,
394    pub reply_broadcast: Option<bool>,
395}
396
397#[skip_serializing_none]
398#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
399pub struct SlackApiChatUpdateResponse {
400    pub channel: SlackChannelId,
401    pub ts: SlackTs,
402    pub thread_ts: Option<SlackTs>,
403    pub message: SlackUpdatedMessage,
404}
405
406#[skip_serializing_none]
407#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
408pub struct SlackApiChatScheduledMessagesListRequest {
409    pub channel: Option<SlackChannelId>,
410    pub cursor: Option<SlackCursorId>,
411    pub latest: Option<SlackTs>,
412    pub limit: Option<u16>,
413    pub oldest: Option<SlackTs>,
414}
415
416#[skip_serializing_none]
417#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
418pub struct SlackApiChatScheduledMessagesListResponse {
419    pub scheduled_messages: Vec<SlackApiChatScheduledMessageInfo>,
420    pub response_metadata: Option<SlackResponseMetadata>,
421}
422
423#[skip_serializing_none]
424#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
425pub struct SlackApiChatScheduledMessageInfo {
426    pub id: SlackScheduledMid,
427    pub channel_id: SlackChannelId,
428    pub post_at: SlackDateTime,
429    pub date_created: SlackDateTime,
430}
431
432impl<SCHC> SlackApiScrollableRequest<SCHC> for SlackApiChatScheduledMessagesListRequest
433where
434    SCHC: SlackClientHttpConnector + Send + Sync + Clone + 'static,
435{
436    type ResponseType = SlackApiChatScheduledMessagesListResponse;
437    type CursorType = SlackCursorId;
438    type ResponseItemType = SlackApiChatScheduledMessageInfo;
439
440    fn with_new_cursor(&self, new_cursor: Option<&Self::CursorType>) -> Self {
441        self.clone().opt_cursor(new_cursor.cloned())
442    }
443
444    fn scroll<'a, 's>(
445        &'a self,
446        session: &'a SlackClientSession<'s, SCHC>,
447    ) -> BoxFuture<'a, ClientResult<Self::ResponseType>> {
448        async move { session.chat_scheduled_messages_list(self).await }.boxed()
449    }
450}
451
452impl SlackApiScrollableResponse for SlackApiChatScheduledMessagesListResponse {
453    type CursorType = SlackCursorId;
454    type ResponseItemType = SlackApiChatScheduledMessageInfo;
455
456    fn next_cursor(&self) -> Option<&Self::CursorType> {
457        self.response_metadata
458            .as_ref()
459            .and_then(|rm| rm.next_cursor.as_ref())
460    }
461
462    fn scrollable_items<'a>(&'a self) -> Box<dyn Iterator<Item = &'a Self::ResponseItemType> + 'a> {
463        Box::new(self.scheduled_messages.iter())
464    }
465}
466
467lazy_static! {
468    pub static ref CHAT_GET_PERMLINK_SPECIAL_LIMIT_RATE_CTL: SlackApiMethodRateControlConfig =
469        SlackApiMethodRateControlConfig::new().with_special_rate_limit(
470            SlackApiRateControlSpecialLimit::new(
471                "chat.getPermalink".into(),
472                SlackApiRateControlLimit::new(100, std::time::Duration::from_secs(1))
473            )
474        );
475    pub static ref CHAT_POST_MESSAGE_SPECIAL_LIMIT_RATE_CTL: SlackApiMethodRateControlConfig =
476        SlackApiMethodRateControlConfig::new().with_special_rate_limit(
477            SlackApiRateControlSpecialLimit::new(
478                "chat.postMessage".into(),
479                SlackApiRateControlLimit::new(1, std::time::Duration::from_secs(1))
480            )
481        );
482}