use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct SlackMessage {
pub text: String,
pub channel: Option<String>,
pub username: Option<String>,
pub icon_emoji: Option<String>,
pub icon_url: Option<String>,
pub attachments: Vec<SlackAttachment>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct SlackAttachment {
pub fallback: Option<String>,
pub color: Option<String>,
pub pretext: Option<String>,
pub author_name: Option<String>,
pub author_link: Option<String>,
pub title: Option<String>,
pub title_link: Option<String>,
pub text: Option<String>,
pub fields: Vec<SlackField>,
pub footer: Option<String>,
pub ts: Option<i64>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SlackField {
pub title: String,
pub value: String,
pub short: bool,
}
impl SlackMessage {
pub fn new(text: impl Into<String>) -> Self {
Self {
text: text.into(),
..Default::default()
}
}
pub fn channel(mut self, channel: impl Into<String>) -> Self {
self.channel = Some(channel.into());
self
}
pub fn username(mut self, username: impl Into<String>) -> Self {
self.username = Some(username.into());
self
}
pub fn icon_emoji(mut self, emoji: impl Into<String>) -> Self {
self.icon_emoji = Some(emoji.into());
self
}
pub fn icon_url(mut self, url: impl Into<String>) -> Self {
self.icon_url = Some(url.into());
self
}
pub fn attachment(mut self, attachment: SlackAttachment) -> Self {
self.attachments.push(attachment);
self
}
}
impl SlackAttachment {
pub fn new() -> Self {
Self::default()
}
pub fn color(mut self, color: impl Into<String>) -> Self {
self.color = Some(color.into());
self
}
pub fn title(mut self, title: impl Into<String>) -> Self {
self.title = Some(title.into());
self
}
pub fn title_link(mut self, link: impl Into<String>) -> Self {
self.title_link = Some(link.into());
self
}
pub fn text(mut self, text: impl Into<String>) -> Self {
self.text = Some(text.into());
self
}
pub fn field(
mut self,
title: impl Into<String>,
value: impl Into<String>,
short: bool,
) -> Self {
self.fields.push(SlackField {
title: title.into(),
value: value.into(),
short,
});
self
}
pub fn footer(mut self, footer: impl Into<String>) -> Self {
self.footer = Some(footer.into());
self
}
pub fn timestamp(mut self, ts: i64) -> Self {
self.ts = Some(ts);
self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_slack_message_builder() {
let msg = SlackMessage::new("Hello, Slack!")
.channel("#general")
.username("MyBot")
.icon_emoji(":robot_face:");
assert_eq!(msg.text, "Hello, Slack!");
assert_eq!(msg.channel, Some("#general".into()));
assert_eq!(msg.username, Some("MyBot".into()));
assert_eq!(msg.icon_emoji, Some(":robot_face:".into()));
}
#[test]
fn test_slack_attachment_builder() {
let attachment = SlackAttachment::new()
.color("good")
.title("Order Placed")
.text("Order #123 has been placed")
.field("Customer", "John Doe", true)
.field("Amount", "$99.99", true);
assert_eq!(attachment.color, Some("good".into()));
assert_eq!(attachment.title, Some("Order Placed".into()));
assert_eq!(attachment.fields.len(), 2);
assert_eq!(attachment.fields[0].title, "Customer");
assert!(attachment.fields[0].short);
}
#[test]
fn test_slack_message_with_attachment() {
let msg = SlackMessage::new("New order received").attachment(
SlackAttachment::new()
.color("#36a64f")
.title("Order Details"),
);
assert_eq!(msg.attachments.len(), 1);
}
}