slack_morphism/models/events/
push.rs

1use rsb_derive::Builder;
2use serde::{Deserialize, Serialize};
3use serde_with::skip_serializing_none;
4use url::Url;
5
6use crate::blocks::*;
7use crate::events::*;
8use crate::models::messages::*;
9use crate::*;
10
11#[allow(clippy::large_enum_variant)]
12#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
13#[serde(tag = "type")]
14pub enum SlackPushEvent {
15    #[serde(rename = "url_verification")]
16    UrlVerification(SlackUrlVerificationEvent),
17    #[serde(rename = "event_callback")]
18    EventCallback(SlackPushEventCallback),
19    #[serde(rename = "app_rate_limited")]
20    AppRateLimited(SlackAppRateLimitedEvent),
21}
22
23#[skip_serializing_none]
24#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
25pub struct SlackUrlVerificationEvent {
26    pub challenge: String,
27}
28
29#[skip_serializing_none]
30#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
31pub struct SlackAppRateLimitedEvent {
32    pub team_id: String,
33    pub minute_rate_limited: SlackDateTime,
34    pub api_app_id: String,
35}
36
37#[skip_serializing_none]
38#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
39pub struct SlackPushEventCallback {
40    pub team_id: SlackTeamId,
41    pub api_app_id: SlackAppId,
42    pub event: SlackEventCallbackBody,
43    pub event_id: SlackEventId,
44    pub event_time: SlackDateTime,
45    pub event_context: Option<SlackEventContext>,
46    pub authed_users: Option<Vec<SlackUserId>>,
47    pub authorizations: Option<Vec<SlackEventAuthorization>>,
48}
49
50#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
51#[serde(tag = "type", rename_all = "snake_case")]
52pub enum SlackEventCallbackBody {
53    Message(SlackMessageEvent),
54    AppHomeOpened(SlackAppHomeOpenedEvent),
55    AppMention(SlackAppMentionEvent),
56    AppUninstalled(SlackAppUninstalledEvent),
57    LinkShared(SlackLinkSharedEvent),
58    EmojiChanged(SlackEmojiChangedEvent),
59    MemberJoinedChannel(SlackMemberJoinedChannelEvent),
60    MemberLeftChannel(SlackMemberLeftChannelEvent),
61    ChannelCreated(SlackChannelCreatedEvent),
62    ChannelDeleted(SlackChannelDeletedEvent),
63    ChannelArchive(SlackChannelArchiveEvent),
64    ChannelRename(SlackChannelRenameEvent),
65    ChannelUnarchive(SlackChannelUnarchiveEvent),
66    TeamJoin(SlackTeamJoinEvent),
67    FileCreated(SlackFileCreatedEvent),
68    FileChange(SlackFileChangedEvent),
69    FileDeleted(SlackFileDeletedEvent),
70    FileShared(SlackFileSharedEvent),
71    FileUnshared(SlackFileUnsharedEvent),
72    FilePublic(SlackFilePublicEvent),
73    ReactionAdded(SlackReactionAddedEvent),
74    ReactionRemoved(SlackReactionRemovedEvent),
75    StarAdded(SlackStarAddedEvent),
76    StarRemoved(SlackStarRemovedEvent),
77    UserChange(SlackUserChangeEvent),
78    UserStatusChanged(SlackUserStatusChangedEvent),
79}
80
81#[skip_serializing_none]
82#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
83pub struct SlackMessageEvent {
84    #[serde(flatten)]
85    pub origin: SlackMessageOrigin,
86    #[serde(flatten)]
87    pub content: Option<SlackMessageContent>,
88    #[serde(flatten)]
89    pub sender: SlackMessageSender,
90    pub subtype: Option<SlackMessageEventType>,
91    pub hidden: Option<bool>,
92    pub message: Option<SlackMessageEventEdited>,
93    pub deleted_ts: Option<SlackTs>,
94}
95
96#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
97pub enum SlackMessageEventType {
98    #[serde(rename = "bot_message")]
99    BotMessage,
100    #[serde(rename = "me_message")]
101    MeMessage,
102    #[serde(rename = "channel_join")]
103    ChannelJoin,
104    #[serde(rename = "channel_leave")]
105    ChannelLeave,
106    #[serde(rename = "bot_add")]
107    BotAdd,
108    #[serde(rename = "bot_remove")]
109    BotRemove,
110    #[serde(rename = "channel_topic")]
111    ChannelTopic,
112    #[serde(rename = "channel_purpose")]
113    ChannelPurpose,
114    #[serde(rename = "channel_name")]
115    ChannelName,
116    #[serde(rename = "file_share")]
117    FileShare,
118    #[serde(rename = "message_changed")]
119    MessageChanged,
120    #[serde(rename = "message_deleted")]
121    MessageDeleted,
122    #[serde(rename = "thread_broadcast")]
123    ThreadBroadcast,
124    #[serde(rename = "tombstone")]
125    Tombstone,
126    #[serde(rename = "joiner_notification")]
127    JoinerNotification,
128    #[serde(rename = "slackbot_response")]
129    SlackbotResponse,
130    #[serde(rename = "emoji_changed")]
131    EmojiChanged,
132    #[serde(rename = "sh_room_created")]
133    SlackHuddleRoomCreated,
134    #[serde(rename = "channel_archive")]
135    ChannelArchive,
136    #[serde(rename = "channel_unarchive")]
137    ChannelUnarchive,
138    #[serde(rename = "app_conversation_leave")]
139    AppConversationLeave,
140    #[serde(rename = "bot_enable")]
141    BotEnable,
142    #[serde(rename = "bot_disable")]
143    BotDisable,
144    #[serde(rename = "pinned_item")]
145    PinnedItem,
146    #[serde(rename = "reminder_add")]
147    ReminderAdd,
148    #[serde(rename = "file_comment")]
149    FileComment,
150    #[serde(rename = "file_created")]
151    FileCreated,
152    #[serde(rename = "file_change")]
153    FileChanged,
154    #[serde(rename = "file_deleted")]
155    FileDeleted,
156    #[serde(rename = "file_shared")]
157    FileShared,
158    #[serde(rename = "file_unshared")]
159    FileUnshared,
160    #[serde(rename = "file_public")]
161    FilePublic,
162    #[serde(rename = "huddle_thread")]
163    HuddleThread,
164    #[serde(rename = "share_shortcut")]
165    ShareShortcut,
166    #[serde(rename = "channel_canvas_updated")]
167    ChannelCanvasUpdated,
168}
169
170#[skip_serializing_none]
171#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
172pub struct SlackAppHomeOpenedEvent {
173    pub user: SlackUserId,
174    pub channel: SlackChannelId,
175    pub tab: String,
176    pub view: Option<SlackView>,
177}
178
179#[skip_serializing_none]
180#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
181pub struct SlackAppMentionEvent {
182    pub user: SlackUserId,
183    pub channel: SlackChannelId,
184    #[serde(flatten)]
185    pub content: SlackMessageContent,
186    #[serde(flatten)]
187    pub origin: SlackMessageOrigin,
188    pub edited: Option<SlackMessageEdited>,
189}
190
191#[skip_serializing_none]
192#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
193pub struct SlackMessageEventEdited {
194    #[serde(flatten)]
195    pub content: Option<SlackMessageContent>,
196    #[serde(flatten)]
197    pub sender: SlackMessageSender,
198    pub ts: SlackTs,
199    pub edited: Option<SlackMessageEdited>,
200}
201
202#[skip_serializing_none]
203#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
204pub struct SlackAppUninstalledEvent {}
205
206#[skip_serializing_none]
207#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
208pub struct SlackLinkSharedEvent {
209    pub channel: SlackChannelId,
210    pub event_ts: SlackTs,
211    pub is_bot_user_member: bool,
212    pub links: Vec<SlackLinkObject>,
213    pub message_ts: SlackTs,
214    pub source: Option<String>,
215    pub unfurl_id: Option<SlackUnfurlId>,
216    pub user: SlackUserId,
217}
218
219#[skip_serializing_none]
220#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
221pub struct SlackEmojiChangedEvent {
222    pub subtype: SlackEmojiEventType,
223    pub name: Option<String>,
224    pub names: Option<Vec<String>>,
225    pub old_name: Option<String>,
226    pub new_name: Option<String>,
227    pub value: Option<Url>,
228    pub event_ts: SlackTs,
229}
230
231#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
232pub enum SlackEmojiEventType {
233    #[serde(rename = "remove")]
234    EmojiRemoved,
235    #[serde(rename = "add")]
236    EmojiAdded,
237    #[serde(rename = "rename")]
238    EmojiRenamed,
239}
240
241#[skip_serializing_none]
242#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
243pub struct SlackLinkObject {
244    pub domain: String,
245    pub url: Url,
246}
247
248#[skip_serializing_none]
249#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
250pub struct SlackMemberJoinedChannelEvent {
251    pub user: SlackUserId,
252    pub channel: SlackChannelId,
253    pub channel_type: SlackChannelType,
254    pub team: SlackTeamId,
255    pub inviter: Option<SlackUserId>,
256}
257
258#[skip_serializing_none]
259#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
260pub struct SlackMemberLeftChannelEvent {
261    pub user: SlackUserId,
262    pub channel: SlackChannelId,
263    pub channel_type: SlackChannelType,
264    pub team: SlackTeamId,
265}
266
267#[skip_serializing_none]
268#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
269pub struct SlackChannelCreatedEvent {
270    pub channel: SlackChannelInfo,
271}
272
273#[skip_serializing_none]
274#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
275pub struct SlackChannelDeletedEvent {
276    pub channel: SlackChannelId,
277}
278
279#[skip_serializing_none]
280#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
281pub struct SlackChannelArchiveEvent {
282    pub channel: SlackChannelId,
283    pub user: SlackUserId,
284}
285
286#[skip_serializing_none]
287#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
288pub struct SlackChannelRenameEvent {
289    pub channel: SlackChannelInfo,
290}
291
292#[skip_serializing_none]
293#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
294pub struct SlackChannelUnarchiveEvent {
295    pub channel: SlackChannelId,
296    pub user: SlackUserId,
297}
298
299#[skip_serializing_none]
300#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
301pub struct SlackTeamJoinEvent {
302    pub user: SlackUser,
303}
304
305#[skip_serializing_none]
306#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
307pub struct SlackFileCreatedEvent {
308    pub user_id: SlackUserId,
309    pub file_id: SlackFileId,
310    pub file: SlackFile,
311}
312
313#[skip_serializing_none]
314#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
315pub struct SlackFileChangedEvent {
316    pub file_id: SlackFileId,
317}
318
319#[skip_serializing_none]
320#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
321pub struct SlackFileDeletedEvent {
322    pub file_id: SlackFileId,
323    pub event_ts: SlackTs,
324}
325
326#[skip_serializing_none]
327#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
328pub struct SlackFileSharedEvent {
329    pub channel_id: SlackChannelId,
330    pub file_id: SlackFileId,
331    pub user_id: SlackUserId,
332    pub event_ts: SlackTs,
333}
334
335#[skip_serializing_none]
336#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
337pub struct SlackFileUnsharedEvent {
338    pub file_id: SlackFileId,
339}
340
341#[skip_serializing_none]
342#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
343pub struct SlackFilePublicEvent {
344    pub file_id: SlackFileId,
345}
346
347#[skip_serializing_none]
348#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
349pub struct SlackReactionAddedEvent {
350    pub user: SlackUserId,
351    pub reaction: SlackReactionName,
352    pub item_user: Option<SlackUserId>,
353    pub item: SlackReactionsItem,
354    pub event_ts: SlackTs,
355}
356
357#[skip_serializing_none]
358#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
359pub struct SlackReactionRemovedEvent {
360    pub user: SlackUserId,
361    pub reaction: SlackReactionName,
362    pub item_user: Option<SlackUserId>,
363    pub item: SlackReactionsItem,
364    pub event_ts: SlackTs,
365}
366
367#[skip_serializing_none]
368#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
369pub struct SlackStarAddedEvent {
370    pub user: SlackUserId,
371    pub item: SlackStarsItem,
372    pub event_ts: SlackTs,
373}
374
375#[skip_serializing_none]
376#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
377pub struct SlackStarRemovedEvent {
378    pub user: SlackUserId,
379    pub item: SlackStarsItem,
380    pub event_ts: SlackTs,
381}
382
383#[skip_serializing_none]
384#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
385pub struct SlackUserChangeEvent {
386    pub user: SlackUser,
387    pub event_ts: SlackTs,
388    pub cache_ts: SlackDateTime,
389}
390
391#[skip_serializing_none]
392#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Builder)]
393pub struct SlackUserStatusChangedEvent {
394    pub user: SlackUser,
395    pub event_ts: SlackTs,
396    pub cache_ts: SlackDateTime,
397}
398
399#[cfg(test)]
400mod test {
401    use super::*;
402
403    #[test]
404    fn test_slack_event_message_change_event() {
405        let payload = include_str!("./fixtures/message_changed.json");
406        let event: SlackPushEventCallback = serde_json::from_str(payload).unwrap();
407        match event.event {
408            SlackEventCallbackBody::Message(SlackMessageEvent {
409                subtype, message, ..
410            }) => {
411                assert_eq!(subtype, Some(SlackMessageEventType::MessageChanged));
412                if let Some(message) = message {
413                    assert_eq!(message.sender.user, Some("UXXXXXXXXXX".into()));
414                    assert_eq!(message.sender.bot_id, None);
415                    assert_eq!(message.ts, "1701735043.989889".into());
416                    assert_eq!(
417                        message.edited.map(|edited| edited.ts),
418                        Some("1701743154.000000".into())
419                    );
420                    assert_eq!(
421                        message.content.unwrap().text,
422                        Some("edited message".to_string())
423                    );
424                } else {
425                    panic!("Message is None");
426                }
427            }
428            _ => panic!("Unexpected event type"),
429        }
430    }
431
432    #[test]
433    fn test_slack_event_message_changed_by_bot_event() {
434        let payload = include_str!("./fixtures/message_changed_by_bot.json");
435        let event: SlackPushEventCallback = serde_json::from_str(payload).unwrap();
436        match event.event {
437            SlackEventCallbackBody::Message(SlackMessageEvent {
438                subtype, message, ..
439            }) => {
440                assert_eq!(subtype, Some(SlackMessageEventType::MessageChanged));
441                if let Some(message) = message {
442                    assert_eq!(message.sender.user, None);
443                    assert_eq!(message.sender.bot_id, Some("BXXXXXXXXXX".into()));
444                    assert_eq!(message.ts, "1701735043.989889".into());
445                    assert_eq!(
446                        message.edited.map(|edited| edited.ts),
447                        Some("1701743154.000000".into())
448                    );
449                    assert_eq!(
450                        message.content.unwrap().text,
451                        Some("edited message".to_string())
452                    );
453                } else {
454                    panic!("Message is None");
455                }
456            }
457            _ => panic!("Unexpected event type"),
458        }
459    }
460}