1use crate::{Error, Message};
2
3#[derive(Clone, Debug)]
10pub struct Client {
11 pub webhook_url: String,
13
14 base_message: Option<Message>,
19
20 http_client: reqwest::Client,
22}
23impl Client {
24 pub async fn deliver(&self, message: Message) -> Result<(), Error> {
26 message.send(&self.http_client).await?;
27
28 Ok(())
29 }
30
31 pub async fn new_message<F>(&self, f: F) -> Option<Message>
35 where
36 F: FnOnce(&mut Message) -> Message,
37 {
38 if let Some(base_message) = &self.base_message {
39 let mut message = base_message.clone();
40
41 let new_message = f(&mut message);
42 Some(new_message)
43 } else {
44 None
45 }
46 }
47}
48impl PartialEq for Client {
49 fn eq(&self, other: &Self) -> bool {
50 self.webhook_url == other.webhook_url
51 }
52}
53impl Eq for Client {}
54
55#[derive(Default)]
56pub struct ClientBuilder {
58 webhook_url: Option<String>,
60
61 baseline_message: Option<Message>,
62}
63impl ClientBuilder {
64 pub fn new() -> ClientBuilder {
66 ClientBuilder::default()
67 }
68
69 pub fn set_webhook_url<S: Into<String>>(mut self, url: S) -> ClientBuilder {
71 self.webhook_url = Some(url.into());
72 self
73 }
74
75 pub fn set_baseline_message(mut self, message: Message) -> ClientBuilder {
76 self.baseline_message = Some(message);
77 self
78 }
79
80 pub fn build(self) -> Result<Client, Error> {
82 if let Some(webhook_url) = self.webhook_url {
83 Ok(Client {
84 webhook_url,
85 http_client: reqwest::Client::new(),
86 base_message: self.baseline_message,
87 })
88 } else {
89 Err(Error::MissingWebhookURL)
90 }
91 }
92}
93
94#[cfg(test)]
95mod tests {
96 use super::*;
97
98 #[test]
99 fn new_returns_default_builder() {
100 let builder = ClientBuilder::new();
101 assert!(builder.webhook_url.is_none());
102 }
103
104 #[test]
105 fn set_webhook_url_sets_url() {
106 let builder = ClientBuilder::new().set_webhook_url("https://hooks.slack.com/abc");
107 assert_eq!(
108 builder.webhook_url,
109 Some("https://hooks.slack.com/abc".to_string())
110 );
111 }
112
113 #[test]
114 fn build_returns_error_if_missing_webhook() {
115 let builder = ClientBuilder::new();
116 let result = builder.build();
117 assert!(matches!(result, Err(Error::MissingWebhookURL)));
118 }
119
120 #[test]
121 fn build_successfully_creates_client() {
122 let builder = ClientBuilder::new()
123 .set_webhook_url("https://hooks.slack.com/xyz")
124 .set_baseline_message(Message::Custom(serde_json::json!({
125 "title": "Warning: detected a tampered token detected.",
126 "description": "A request with a tampered token was used by IP: xxx.xx.xx.xxx",
127 })));
128 let client = builder.build().expect("Expected successful build");
129 let base_message = Message::Custom(serde_json::json!({
130 "title": "Warning: detected a tampered token detected.",
131 "description": "A request with a tampered token was used by IP: xxx.xx.xx.xxx",
132 }));
133
134 assert_eq!(
135 client,
136 Client {
137 webhook_url: "https://hooks.slack.com/xyz".into(),
138 http_client: reqwest::Client::new(),
139 base_message: Some(base_message)
140 }
141 );
142 }
143}