Skip to main content

clickup_cli/commands/
acl.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 AclCommands {
11    /// Update ACL for an object (Enterprise only, v3)
12    Update {
13        /// Object type (e.g. task, list, folder, space)
14        object_type: String,
15        /// Object ID
16        object_id: String,
17        /// Make the object private
18        #[arg(long)]
19        private: bool,
20        /// Grant access to a user ID (use with --permission)
21        #[arg(long)]
22        grant_user: Option<String>,
23        /// Permission level for --grant-user (e.g. read, comment, edit, create)
24        #[arg(long)]
25        permission: Option<String>,
26        /// Revoke access from a user ID
27        #[arg(long)]
28        revoke_user: Option<String>,
29        /// Raw JSON body (overrides all other flags)
30        #[arg(long)]
31        body: Option<String>,
32    },
33}
34
35pub async fn execute(command: AclCommands, cli: &Cli) -> Result<(), CliError> {
36    let token = resolve_token(cli)?;
37    let client = ClickUpClient::new(&token, cli.timeout)?;
38    let output = OutputConfig::from_cli(&cli.output, &cli.fields, cli.no_header, cli.quiet);
39
40    match command {
41        AclCommands::Update {
42            object_type,
43            object_id,
44            private,
45            grant_user,
46            permission,
47            revoke_user,
48            body,
49        } => {
50            let team_id = resolve_workspace(cli)?;
51            let request_body = if let Some(raw) = body {
52                serde_json::from_str(&raw).map_err(|e| CliError::ClientError {
53                    message: format!("Invalid JSON body: {}", e),
54                    status: 0,
55                })?
56            } else {
57                let mut b = serde_json::Map::new();
58                if private {
59                    b.insert(
60                        "access_type".into(),
61                        serde_json::Value::String("private".into()),
62                    );
63                }
64                if let Some(uid) = grant_user {
65                    let level = permission.unwrap_or_else(|| "read".into());
66                    b.insert(
67                        "grant".into(),
68                        serde_json::json!([{ "user_id": uid, "permission_level": level }]),
69                    );
70                }
71                if let Some(uid) = revoke_user {
72                    b.insert("revoke".into(), serde_json::json!([{ "user_id": uid }]));
73                }
74                serde_json::Value::Object(b)
75            };
76
77            let resp = client
78                .patch(
79                    &format!(
80                        "/v3/workspaces/{}/{}/{}/acls",
81                        team_id, object_type, object_id
82                    ),
83                    &request_body,
84                )
85                .await?;
86
87            if cli.output == "json" {
88                println!("{}", serde_json::to_string_pretty(&resp).unwrap());
89            } else {
90                output.print_message(&format!("ACL updated for {} {}", object_type, object_id));
91            }
92            Ok(())
93        }
94    }
95}