flawless_slack/lib.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
#![doc = include_str!("../Readme.md")]
pub mod http_client;
use http_client::{HttpClient, HttpClientError};
use serde::Deserialize;
/// Represents a Slack client that interacts with the Slack API using the provided HTTP client.
pub struct SlackClient<T: HttpClient> {
token: String,
client: T,
}
/// Represents errors that can occur during interactions with the Slack API.
#[derive(Debug)]
pub enum SlackClientError {
/// Error related to HTTP client operations.
HttpClientError(HttpClientError),
/// Error related to JSON deserialization.
JsonError(serde_json::Error),
/// Generic error with a descriptive string.
Error(String),
}
impl From<serde_json::Error> for SlackClientError {
fn from(err: serde_json::Error) -> Self {
SlackClientError::JsonError(err)
}
}
impl From<HttpClientError> for SlackClientError {
fn from(err: HttpClientError) -> Self {
SlackClientError::HttpClientError(err)
}
}
/// Represents an element in a Slack message block.
#[derive(Debug, Deserialize)]
pub struct Element {
/// The type of the element.
#[serde(rename = "type")]
pub element_type: String,
/// The text content of the element.
pub text: Option<String>,
}
/// Represents a block in a Slack message.
#[derive(Debug, Deserialize)]
pub struct Block {
/// The type of the block.
#[serde(rename = "type")]
pub block_type: String,
/// The unique identifier of the block.
pub block_id: String,
/// Elements within the block.
pub elements: Vec<Element>,
}
/// Represents a Slack message.
#[derive(Debug, Deserialize)]
pub struct Message {
#[serde(default)]
/// The ID of the bot that sent the message.
pub bot_id: Option<String>,
/// The user who sent the message.
pub user: String,
/// The text content of the message.
pub text: Option<String>,
/// The timestamp of the message.
pub ts: Option<String>,
}
/// Represents the response structure when getting messages from Slack.
#[derive(Debug, Deserialize)]
struct GetMessagesResponse {
/// The list of messages retrieved from Slack.
messages: Vec<Message>,
}
/// Represents a Slack channel.
#[derive(Debug, Deserialize)]
pub struct Channel {
/// The unique identifier of the channel.
id: String,
/// The name of the channel.
name: String,
}
#[derive(Debug, Deserialize)]
struct ListConversationsResponse {
channels: Vec<Channel>,
}
impl<T: HttpClient> SlackClient<T> {
/// Creates a new instance of `SlackClient` with the specified token and HTTP client.
///
/// # Arguments
///
/// * `token` - A String containing the Slack API token.
/// * `client` - An HTTP client implementing the `HttpClient` trait.
///
/// # Returns
///
/// A new instance of `SlackClient`.
pub fn new(token: String, client: T) -> SlackClient<T> {
SlackClient { token, client }
}
/// Sends a message to a Slack channel.
///
/// # Arguments
///
/// * `channel` - The name or ID of the channel where the message will be sent.
/// * `text` - The text of the message to be sent.
///
/// # Returns
///
/// Returns `Ok(())` on success, or an error of type `SlackClientError` on failure.
pub fn send_message(&self, channel: &str, text: &str) -> Result<(), SlackClientError> {
let url = "https://slack.com/api/chat.postMessage";
let token = format!("Bearer {}", self.token);
let params = [("Authorization", token.as_str()), ("Content-Type", "application/json")];
let payload = format!("{{\"channel\": \"{}\", \"text\": \"{}\"}}", channel, text);
let result = self.client.post(url, ¶ms, &payload);
result.map_err(SlackClientError::HttpClientError).map(|response| {
if response.contains("\"ok\":false") {
Err(SlackClientError::Error(response))
} else {
Ok(())
}
})?
}
/// Retrieves messages from a Slack channel.
///
/// # Arguments
///
/// * `channel` - The name or ID of the channel from which to retrieve messages.
///
/// # Returns
///
/// Returns a vector of `Message` on success, or an error of type `SlackClientError` on failure.
pub fn get_messages(&self, channel: &str) -> Result<Vec<Message>, SlackClientError> {
let url = "https://slack.com/api/conversations.history";
let token = format!("Bearer {}", self.token);
let params = [("Authorization", token.as_str()), ("Content-Type", "application/json")];
let mut channel_id = channel.to_string();
if channel.starts_with('#') {
let channels = self.get_channels()?;
channel_id = channels.iter().find(|c| c.name == channel[1..]).unwrap().id.clone();
}
let queries = [("channel", channel_id.as_str())];
let response = self.client.get(url, ¶ms, &queries)?;
let result: GetMessagesResponse = serde_json::from_str(&response)?;
Ok(result.messages)
}
/// Retrieves a list of Slack channels.
///
/// # Returns
///
/// Returns a vector of `Channel` on success, or an error of type `SlackClientError` on failure.
pub fn get_channels(&self) -> Result<Vec<Channel>, SlackClientError> {
let url = "https://slack.com/api/conversations.list";
let token = format!("Bearer {}", self.token);
let params = [("Authorization", token.as_str()), ("Content-Type", "application/json")];
let response = self.client.get(url, ¶ms, &[])?;
let result: ListConversationsResponse = serde_json::from_str(&response)?;
Ok(result.channels)
}
}