Skip to main content

clickup_cli/commands/
auth.rs

1use crate::client::ClickUpClient;
2use crate::config::Config;
3use crate::error::CliError;
4use crate::output::OutputConfig;
5use crate::Cli;
6use clap::Subcommand;
7
8#[derive(Subcommand)]
9pub enum AuthCommands {
10    /// Show current user info
11    Whoami,
12    /// Quick token validation (exit code only)
13    Check,
14}
15
16pub async fn execute(command: AuthCommands, cli: &Cli) -> Result<(), CliError> {
17    let token = resolve_token(cli)?;
18    let client = ClickUpClient::new(&token, cli.timeout)?;
19
20    match command {
21        AuthCommands::Whoami => {
22            let resp = client.get("/v2/user").await?;
23            let output = OutputConfig::from_cli(&cli.output, &cli.fields, cli.no_header, cli.quiet);
24            if let Some(user) = resp.get("user") {
25                output.print_single(user, &["id", "username", "email"], "id");
26            }
27            Ok(())
28        }
29        AuthCommands::Check => {
30            // Just hit the endpoint — success = exit 0, failure = error propagates
31            client.get("/v2/user").await?;
32            Ok(())
33        }
34    }
35}
36
37pub fn resolve_token(cli: &Cli) -> Result<String, CliError> {
38    // 1. --token flag (highest priority)
39    if let Some(token) = &cli.token {
40        return Ok(token.clone());
41    }
42    // 2. CLICKUP_TOKEN env var
43    if let Ok(token) = std::env::var("CLICKUP_TOKEN") {
44        if !token.is_empty() {
45            return Ok(token);
46        }
47    }
48    // 3. Config file
49    let config = Config::load()?;
50    if config.auth.token.is_empty() {
51        return Err(CliError::ConfigError("Not configured".into()));
52    }
53    Ok(config.auth.token)
54}