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}