Skip to main content

clickup_cli/commands/
webhook.rs

1use crate::client::ClickUpClient;
2use crate::commands::auth::resolve_token;
3use crate::commands::workspace::resolve_workspace;
4use crate::error::CliError;
5use crate::output::OutputConfig;
6use crate::Cli;
7use clap::Subcommand;
8
9#[derive(Subcommand)]
10pub enum WebhookCommands {
11    /// List webhooks for the workspace
12    List,
13    /// Create a webhook
14    Create {
15        /// Endpoint URL
16        #[arg(long)]
17        endpoint: String,
18        /// Event(s) to subscribe to (can be repeated)
19        #[arg(long = "event")]
20        events: Vec<String>,
21        /// Scope to a specific space ID
22        #[arg(long)]
23        space: Option<String>,
24        /// Scope to a specific folder ID
25        #[arg(long)]
26        folder: Option<String>,
27        /// Scope to a specific list ID
28        #[arg(long)]
29        list: Option<String>,
30        /// Scope to a specific task ID
31        #[arg(long)]
32        task: Option<String>,
33    },
34    /// Update a webhook
35    Update {
36        /// Webhook ID
37        id: String,
38        /// New endpoint URL
39        #[arg(long)]
40        endpoint: String,
41        /// Event(s) to subscribe to (can be repeated)
42        #[arg(long = "event")]
43        events: Vec<String>,
44        /// Webhook status: active or inactive
45        #[arg(long, default_value = "active")]
46        status: String,
47    },
48    /// Delete a webhook
49    Delete {
50        /// Webhook ID
51        id: String,
52    },
53}
54
55const WEBHOOK_FIELDS: &[&str] = &["id", "endpoint", "status", "events"];
56
57pub async fn execute(command: WebhookCommands, cli: &Cli) -> Result<(), CliError> {
58    let token = resolve_token(cli)?;
59    let client = ClickUpClient::new(&token, cli.timeout)?;
60    let output = OutputConfig::from_cli(&cli.output, &cli.fields, cli.no_header, cli.quiet);
61
62    match command {
63        WebhookCommands::List => {
64            let ws_id = resolve_workspace(cli)?;
65            let resp = client.get(&format!("/v2/team/{}/webhook", ws_id)).await?;
66            let mut webhooks = resp
67                .get("webhooks")
68                .and_then(|v| v.as_array())
69                .cloned()
70                .unwrap_or_default();
71            if let Some(limit) = cli.limit {
72                webhooks.truncate(limit);
73            }
74            output.print_items(&webhooks, WEBHOOK_FIELDS, "id");
75            Ok(())
76        }
77        WebhookCommands::Create {
78            endpoint,
79            events,
80            space,
81            folder,
82            list,
83            task,
84        } => {
85            let ws_id = resolve_workspace(cli)?;
86            let mut body = serde_json::json!({
87                "endpoint": endpoint,
88                "events": events,
89            });
90            if let Some(s) = space {
91                body["space_id"] = serde_json::Value::String(s);
92            }
93            if let Some(f) = folder {
94                body["folder_id"] = serde_json::Value::String(f);
95            }
96            if let Some(l) = list {
97                body["list_id"] = serde_json::Value::String(l);
98            }
99            if let Some(t) = task {
100                body["task_id"] = serde_json::Value::String(t);
101            }
102            let resp = client
103                .post(&format!("/v2/team/{}/webhook", ws_id), &body)
104                .await?;
105            output.print_single(&resp, WEBHOOK_FIELDS, "id");
106            Ok(())
107        }
108        WebhookCommands::Update {
109            id,
110            endpoint,
111            events,
112            status,
113        } => {
114            let body = serde_json::json!({
115                "endpoint": endpoint,
116                "events": events,
117                "status": status,
118            });
119            let resp = client.put(&format!("/v2/webhook/{}", id), &body).await?;
120            output.print_single(&resp, WEBHOOK_FIELDS, "id");
121            Ok(())
122        }
123        WebhookCommands::Delete { id } => {
124            client.delete(&format!("/v2/webhook/{}", id)).await?;
125            output.print_message(&format!("Webhook {} deleted", id));
126            Ok(())
127        }
128    }
129}