use std::collections::HashMap;
use serde::{Deserialize, Serialize};
use crate::{
emoji::EmojiValue,
message::{Author, IncomingMessage},
};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ActionEvent {
pub action_id: String,
pub thread_id: String,
pub message_id: String,
pub user: Author,
pub value: Option<String>,
pub trigger_id: Option<String>,
pub adapter_name: String,
}
#[derive(Debug, Clone)]
pub struct ReactionEvent {
pub thread_id: String,
pub message_id: String,
pub user: Author,
pub emoji: EmojiValue,
pub added: bool,
pub adapter_name: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SlashCommandEvent {
pub command: String,
pub text: String,
pub channel_id: String,
pub user: Author,
pub trigger_id: Option<String>,
pub adapter_name: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ModalSubmitEvent {
pub callback_id: String,
pub view_id: String,
pub user: Author,
pub values: HashMap<String, String>,
pub private_metadata: Option<String>,
pub adapter_name: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ModalCloseEvent {
pub callback_id: String,
pub view_id: String,
pub user: Author,
pub adapter_name: String,
}
#[derive(Debug, Clone)]
pub enum ChatEvent {
Message {
thread_id: String,
message: IncomingMessage,
},
Mention {
thread_id: String,
message: IncomingMessage,
},
Reaction(ReactionEvent),
Action(ActionEvent),
SlashCommand(SlashCommandEvent),
ModalSubmit(ModalSubmitEvent),
ModalClose(ModalCloseEvent),
}
#[cfg(test)]
mod tests {
use super::*;
fn sample_author() -> Author {
Author {
user_id: "u1".into(),
user_name: "alice".into(),
full_name: "Alice".into(),
is_bot: false,
}
}
fn sample_incoming() -> IncomingMessage {
IncomingMessage {
id: "m1".into(),
text: "hello".into(),
author: sample_author(),
attachments: vec![],
is_mention: false,
thread_id: "t1".into(),
timestamp: None,
}
}
#[test]
fn chat_event_message_variant() {
let event = ChatEvent::Message { thread_id: "t1".into(), message: sample_incoming() };
assert!(matches!(event, ChatEvent::Message { .. }));
}
#[test]
fn chat_event_mention_variant() {
let event = ChatEvent::Mention { thread_id: "t1".into(), message: sample_incoming() };
assert!(matches!(event, ChatEvent::Mention { .. }));
}
#[test]
fn chat_event_action_variant() {
let event = ChatEvent::Action(ActionEvent {
action_id: "btn_approve".into(),
thread_id: "t1".into(),
message_id: "m1".into(),
user: sample_author(),
value: Some("yes".into()),
trigger_id: None,
adapter_name: "slack".into(),
});
assert!(matches!(event, ChatEvent::Action(_)));
}
#[test]
fn chat_event_slash_command_variant() {
let event = ChatEvent::SlashCommand(SlashCommandEvent {
command: "/deploy".into(),
text: "prod".into(),
channel_id: "c1".into(),
user: sample_author(),
trigger_id: None,
adapter_name: "slack".into(),
});
assert!(matches!(event, ChatEvent::SlashCommand(_)));
}
#[test]
fn chat_event_modal_submit_variant() {
let event = ChatEvent::ModalSubmit(ModalSubmitEvent {
callback_id: "feedback".into(),
view_id: "v1".into(),
user: sample_author(),
values: HashMap::from([("rating".into(), "5".into())]),
private_metadata: None,
adapter_name: "slack".into(),
});
assert!(matches!(event, ChatEvent::ModalSubmit(_)));
}
#[test]
fn chat_event_modal_close_variant() {
let event = ChatEvent::ModalClose(ModalCloseEvent {
callback_id: "feedback".into(),
view_id: "v1".into(),
user: sample_author(),
adapter_name: "slack".into(),
});
assert!(matches!(event, ChatEvent::ModalClose(_)));
}
#[test]
fn chat_event_clone_and_debug() {
let event = ChatEvent::Action(ActionEvent {
action_id: "a".into(),
thread_id: "t".into(),
message_id: "m".into(),
user: sample_author(),
value: None,
trigger_id: None,
adapter_name: "test".into(),
});
let cloned = event.clone();
let dbg = format!("{cloned:?}");
assert!(!dbg.is_empty());
}
}