Skip to main content

clickup_cli/commands/
guest.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 GuestCommands {
11    /// Invite a guest to the workspace (Enterprise only)
12    Invite {
13        /// Guest email address
14        #[arg(long)]
15        email: String,
16        /// Allow guest to edit tags
17        #[arg(long)]
18        can_edit_tags: bool,
19        /// Allow guest to see time spent
20        #[arg(long)]
21        can_see_time_spent: bool,
22        /// Allow guest to create views
23        #[arg(long)]
24        can_create_views: bool,
25        /// Custom role ID to assign
26        #[arg(long)]
27        custom_role_id: Option<u64>,
28    },
29    /// Get a guest by ID
30    Get {
31        /// Guest ID
32        id: String,
33    },
34    /// Update guest permissions
35    Update {
36        /// Guest ID
37        id: String,
38        /// Allow guest to edit tags
39        #[arg(long)]
40        can_edit_tags: Option<bool>,
41        /// Allow guest to see time spent
42        #[arg(long)]
43        can_see_time_spent: Option<bool>,
44        /// Allow guest to create views
45        #[arg(long)]
46        can_create_views: Option<bool>,
47        /// Custom role ID to assign
48        #[arg(long)]
49        custom_role_id: Option<u64>,
50    },
51    /// Remove a guest from the workspace
52    Remove {
53        /// Guest ID
54        id: String,
55    },
56    /// Share a task with a guest
57    ShareTask {
58        /// Task ID
59        task_id: String,
60        /// Guest ID
61        guest_id: String,
62        /// Permission level: read, comment, edit, create
63        #[arg(long)]
64        permission: String,
65    },
66    /// Unshare a task from a guest
67    UnshareTask {
68        /// Task ID
69        task_id: String,
70        /// Guest ID
71        guest_id: String,
72    },
73    /// Share a list with a guest
74    ShareList {
75        /// List ID
76        list_id: String,
77        /// Guest ID
78        guest_id: String,
79        /// Permission level: read, comment, edit, create
80        #[arg(long)]
81        permission: String,
82    },
83    /// Unshare a list from a guest
84    UnshareList {
85        /// List ID
86        list_id: String,
87        /// Guest ID
88        guest_id: String,
89    },
90    /// Share a folder with a guest
91    ShareFolder {
92        /// Folder ID
93        folder_id: String,
94        /// Guest ID
95        guest_id: String,
96        /// Permission level: read, comment, edit, create
97        #[arg(long)]
98        permission: String,
99    },
100    /// Unshare a folder from a guest
101    UnshareFolder {
102        /// Folder ID
103        folder_id: String,
104        /// Guest ID
105        guest_id: String,
106    },
107}
108
109const GUEST_FIELDS: &[&str] = &["id", "username", "email", "role"];
110
111pub async fn execute(command: GuestCommands, cli: &Cli) -> Result<(), CliError> {
112    let token = resolve_token(cli)?;
113    let client = ClickUpClient::new(&token, cli.timeout)?;
114    let output = OutputConfig::from_cli(&cli.output, &cli.fields, cli.no_header, cli.quiet);
115
116    match command {
117        GuestCommands::Invite {
118            email,
119            can_edit_tags,
120            can_see_time_spent,
121            can_create_views,
122            custom_role_id,
123        } => {
124            let team_id = resolve_workspace(cli)?;
125            let mut body = serde_json::json!({
126                "email": email,
127                "can_edit_tags": can_edit_tags,
128                "can_see_time_spent": can_see_time_spent,
129                "can_create_views": can_create_views,
130            });
131            if let Some(role_id) = custom_role_id {
132                body["custom_role_id"] = serde_json::Value::Number(role_id.into());
133            }
134            let resp = client
135                .post(&format!("/v2/team/{}/guest", team_id), &body)
136                .await?;
137            let guest = resp.get("guest").cloned().unwrap_or(resp);
138            output.print_single(&guest, GUEST_FIELDS, "id");
139            Ok(())
140        }
141        GuestCommands::Get { id } => {
142            let team_id = resolve_workspace(cli)?;
143            let resp = client
144                .get(&format!("/v2/team/{}/guest/{}", team_id, id))
145                .await?;
146            let guest = resp.get("guest").cloned().unwrap_or(resp);
147            output.print_single(&guest, GUEST_FIELDS, "id");
148            Ok(())
149        }
150        GuestCommands::Update {
151            id,
152            can_edit_tags,
153            can_see_time_spent,
154            can_create_views,
155            custom_role_id,
156        } => {
157            let team_id = resolve_workspace(cli)?;
158            let mut body = serde_json::Map::new();
159            if let Some(v) = can_edit_tags {
160                body.insert("can_edit_tags".into(), serde_json::Value::Bool(v));
161            }
162            if let Some(v) = can_see_time_spent {
163                body.insert("can_see_time_spent".into(), serde_json::Value::Bool(v));
164            }
165            if let Some(v) = can_create_views {
166                body.insert("can_create_views".into(), serde_json::Value::Bool(v));
167            }
168            if let Some(v) = custom_role_id {
169                body.insert("custom_role_id".into(), serde_json::Value::Number(v.into()));
170            }
171            let resp = client
172                .put(
173                    &format!("/v2/team/{}/guest/{}", team_id, id),
174                    &serde_json::Value::Object(body),
175                )
176                .await?;
177            let guest = resp.get("guest").cloned().unwrap_or(resp);
178            output.print_single(&guest, GUEST_FIELDS, "id");
179            Ok(())
180        }
181        GuestCommands::Remove { id } => {
182            let team_id = resolve_workspace(cli)?;
183            client
184                .delete(&format!("/v2/team/{}/guest/{}", team_id, id))
185                .await?;
186            output.print_message(&format!("Guest {} removed from workspace", id));
187            Ok(())
188        }
189        GuestCommands::ShareTask {
190            task_id,
191            guest_id,
192            permission,
193        } => {
194            let body = serde_json::json!({ "permission_level": permission });
195            let resp = client
196                .post(&format!("/v2/task/{}/guest/{}", task_id, guest_id), &body)
197                .await?;
198            output.print_single(&resp, GUEST_FIELDS, "id");
199            Ok(())
200        }
201        GuestCommands::UnshareTask { task_id, guest_id } => {
202            client
203                .delete(&format!("/v2/task/{}/guest/{}", task_id, guest_id))
204                .await?;
205            output.print_message(&format!(
206                "Guest {} unshared from task {}",
207                guest_id, task_id
208            ));
209            Ok(())
210        }
211        GuestCommands::ShareList {
212            list_id,
213            guest_id,
214            permission,
215        } => {
216            let body = serde_json::json!({ "permission_level": permission });
217            let resp = client
218                .post(&format!("/v2/list/{}/guest/{}", list_id, guest_id), &body)
219                .await?;
220            output.print_single(&resp, GUEST_FIELDS, "id");
221            Ok(())
222        }
223        GuestCommands::UnshareList { list_id, guest_id } => {
224            client
225                .delete(&format!("/v2/list/{}/guest/{}", list_id, guest_id))
226                .await?;
227            output.print_message(&format!(
228                "Guest {} unshared from list {}",
229                guest_id, list_id
230            ));
231            Ok(())
232        }
233        GuestCommands::ShareFolder {
234            folder_id,
235            guest_id,
236            permission,
237        } => {
238            let body = serde_json::json!({ "permission_level": permission });
239            let resp = client
240                .post(
241                    &format!("/v2/folder/{}/guest/{}", folder_id, guest_id),
242                    &body,
243                )
244                .await?;
245            output.print_single(&resp, GUEST_FIELDS, "id");
246            Ok(())
247        }
248        GuestCommands::UnshareFolder {
249            folder_id,
250            guest_id,
251        } => {
252            client
253                .delete(&format!("/v2/folder/{}/guest/{}", folder_id, guest_id))
254                .await?;
255            output.print_message(&format!(
256                "Guest {} unshared from folder {}",
257                guest_id, folder_id
258            ));
259            Ok(())
260        }
261    }
262}