Skip to main content

slack_rs/commands/
react.rs

1//! Reaction command implementations
2
3use crate::api::{ApiClient, ApiError, ApiMethod, ApiResponse};
4use crate::commands::guards::{check_write_allowed, confirm_destructive_with_hint};
5use serde_json::json;
6use std::collections::HashMap;
7
8/// Add a reaction to a message
9///
10/// # Arguments
11/// * `client` - API client
12/// * `channel` - Channel ID
13/// * `timestamp` - Message timestamp
14/// * `name` - Emoji name (without colons, e.g., "thumbsup")
15/// * `yes` - Skip confirmation prompt
16/// * `non_interactive` - Whether running in non-interactive mode
17///
18/// # Returns
19/// * `Ok(ApiResponse)` with reaction confirmation
20/// * `Err(ApiError)` if the operation fails
21pub async fn react_add(
22    client: &ApiClient,
23    channel: String,
24    timestamp: String,
25    name: String,
26    yes: bool,
27    non_interactive: bool,
28) -> Result<ApiResponse, ApiError> {
29    check_write_allowed()?;
30
31    // Build hint with example command for non-interactive mode
32    let hint = format!(
33        "Example: slack-rs react add {} {} {} --yes",
34        channel, timestamp, name
35    );
36    confirm_destructive_with_hint(yes, "add this reaction", non_interactive, Some(&hint))?;
37
38    let mut params = HashMap::new();
39    params.insert("channel".to_string(), json!(channel));
40    params.insert("timestamp".to_string(), json!(timestamp));
41    params.insert("name".to_string(), json!(name));
42
43    client.call_method(ApiMethod::ReactionsAdd, params).await
44}
45
46/// Remove a reaction from a message
47///
48/// # Arguments
49/// * `client` - API client
50/// * `channel` - Channel ID
51/// * `timestamp` - Message timestamp
52/// * `name` - Emoji name (without colons, e.g., "thumbsup")
53/// * `yes` - Skip confirmation prompt
54/// * `non_interactive` - Whether running in non-interactive mode
55///
56/// # Returns
57/// * `Ok(ApiResponse)` with removal confirmation
58/// * `Err(ApiError)` if the operation fails
59pub async fn react_remove(
60    client: &ApiClient,
61    channel: String,
62    timestamp: String,
63    name: String,
64    yes: bool,
65    non_interactive: bool,
66) -> Result<ApiResponse, ApiError> {
67    check_write_allowed()?;
68
69    // Build hint with example command for non-interactive mode
70    let hint = format!(
71        "Example: slack-rs react remove {} {} {} --yes",
72        channel, timestamp, name
73    );
74    confirm_destructive_with_hint(yes, "remove this reaction", non_interactive, Some(&hint))?;
75
76    let mut params = HashMap::new();
77    params.insert("channel".to_string(), json!(channel));
78    params.insert("timestamp".to_string(), json!(timestamp));
79    params.insert("name".to_string(), json!(name));
80
81    client.call_method(ApiMethod::ReactionsRemove, params).await
82}
83
84#[cfg(test)]
85mod tests {
86    use super::*;
87    use serial_test::serial;
88
89    #[tokio::test]
90    #[serial(write_guard)]
91    async fn test_react_add_with_env_false() {
92        std::env::set_var("SLACKCLI_ALLOW_WRITE", "false");
93        let client = ApiClient::with_token("test_token".to_string());
94        let result = react_add(
95            &client,
96            "C123456".to_string(),
97            "1234567890.123456".to_string(),
98            "thumbsup".to_string(),
99            true,
100            false,
101        )
102        .await;
103        assert!(result.is_err());
104        assert!(matches!(result.unwrap_err(), ApiError::WriteNotAllowed));
105        std::env::remove_var("SLACKCLI_ALLOW_WRITE");
106    }
107
108    #[tokio::test]
109    #[serial(write_guard)]
110    async fn test_react_remove_with_env_false() {
111        std::env::set_var("SLACKCLI_ALLOW_WRITE", "false");
112        let client = ApiClient::with_token("test_token".to_string());
113        let result = react_remove(
114            &client,
115            "C123456".to_string(),
116            "1234567890.123456".to_string(),
117            "thumbsup".to_string(),
118            true,
119            false,
120        )
121        .await;
122        assert!(result.is_err());
123        assert!(matches!(result.unwrap_err(), ApiError::WriteNotAllowed));
124        std::env::remove_var("SLACKCLI_ALLOW_WRITE");
125    }
126}