1#![doc = include_str!("../Readme.md")]
2
3pub mod http_client;
4
5use http_client::{HttpClient, HttpClientError};
6
7use serde::Deserialize;
8
9pub struct SlackClient<T: HttpClient> {
11 token: String,
12 client: T,
13}
14
15#[derive(Debug)]
17pub enum SlackClientError {
18 HttpClientError(HttpClientError),
20 JsonError(serde_json::Error),
22 Error(String),
24}
25
26impl From<serde_json::Error> for SlackClientError {
27 fn from(err: serde_json::Error) -> Self {
28 SlackClientError::JsonError(err)
29 }
30}
31
32impl From<HttpClientError> for SlackClientError {
33 fn from(err: HttpClientError) -> Self {
34 SlackClientError::HttpClientError(err)
35 }
36}
37
38#[derive(Debug, Deserialize)]
40pub struct Element {
41 #[serde(rename = "type")]
43 pub element_type: String,
44 pub text: Option<String>,
46}
47
48#[derive(Debug, Deserialize)]
50pub struct Block {
51 #[serde(rename = "type")]
53 pub block_type: String,
54 pub block_id: String,
56 pub elements: Vec<Element>,
58}
59
60#[derive(Debug, Deserialize)]
62pub struct Message {
63 #[serde(default)]
64 pub bot_id: Option<String>,
66 pub user: String,
68 pub text: Option<String>,
70 pub ts: Option<String>,
72}
73
74#[derive(Debug, Deserialize)]
76struct GetMessagesResponse {
77 messages: Vec<Message>,
79}
80
81#[derive(Debug, Deserialize)]
83pub struct Channel {
84 id: String,
86 name: String,
88}
89
90#[derive(Debug, Deserialize)]
91struct ListConversationsResponse {
92 channels: Vec<Channel>,
93}
94
95impl<T: HttpClient> SlackClient<T> {
96 pub fn new(token: String, client: T) -> SlackClient<T> {
107 SlackClient { token, client }
108 }
109
110 pub fn send_message(&self, channel: &str, text: &str) -> Result<(), SlackClientError> {
121 let url = "https://slack.com/api/chat.postMessage";
122
123 let token = format!("Bearer {}", self.token);
124 let params = [("Authorization", token.as_str()), ("Content-Type", "application/json")];
125
126 let payload = format!("{{\"channel\": \"{}\", \"text\": \"{}\"}}", channel, text);
127
128 let result = self.client.post(url, ¶ms, &payload);
129
130 result.map_err(SlackClientError::HttpClientError).map(|response| {
131 if response.contains("\"ok\":false") {
132 Err(SlackClientError::Error(response))
133 } else {
134 Ok(())
135 }
136 })?
137 }
138
139 pub fn get_messages(&self, channel: &str) -> Result<Vec<Message>, SlackClientError> {
149 let url = "https://slack.com/api/conversations.history";
150
151 let token = format!("Bearer {}", self.token);
152 let params = [("Authorization", token.as_str()), ("Content-Type", "application/json")];
153
154 let mut channel_id = channel.to_string();
155 if channel.starts_with('#') {
156 let channels = self.get_channels()?;
157 channel_id = channels.iter().find(|c| c.name == channel[1..]).unwrap().id.clone();
158 }
159
160 let queries = [("channel", channel_id.as_str())];
161
162 let response = self.client.get(url, ¶ms, &queries)?;
163
164 let result: GetMessagesResponse = serde_json::from_str(&response)?;
165
166 Ok(result.messages)
167 }
168
169 pub fn get_channels(&self) -> Result<Vec<Channel>, SlackClientError> {
175 let url = "https://slack.com/api/conversations.list";
176
177 let token = format!("Bearer {}", self.token);
178 let params = [("Authorization", token.as_str()), ("Content-Type", "application/json")];
179
180 let response = self.client.get(url, ¶ms, &[])?;
181
182 let result: ListConversationsResponse = serde_json::from_str(&response)?;
183
184 Ok(result.channels)
185 }
186}