zero-cli 1.0.1

A command line tool for Zero Secrets Manager
mod graphql;

use crate::common::{
    authorization_headers::authorization_headers, execute_graphql_request::execute_graphql_request,
    fetch_user_id::fetch_user_id, keyring::keyring, lengify::lengify,
    pagination_list::pagination_list, print_formatted_error::print_formatted_error,
};
use clap::Args;
use dialoguer::{theme::ColorfulTheme, Select};
use graphql::my_teams::{my_teams, MyTeams};
use graphql::shared_teams::{shared_teams, SharedTeams};
use graphql_client::GraphQLQuery;
use reqwest::Client;
use termimad::crossterm::style::Stylize;

#[derive(Args, Debug)]
pub struct TeamListArgs {
    #[clap(
        short,
        long,
        help = "Access token, if not specified, the token will be taken from the keychain"
    )]
    access_token: Option<String>,
}

enum TeamsOwnership {
    MyTeams,
    SharedTeams,
}

impl TeamsOwnership {
    fn get_all_values() -> Vec<String> {
        vec!["My Teams".to_string(), "Shared Teams".to_string()]
    }
}

pub fn list(args: &TeamListArgs) {
    let access_token = match &args.access_token {
        Some(token) => token.clone(),
        None => keyring::get("access_token"),
    };

    let from_team = Select::with_theme(&ColorfulTheme::default())
        .with_prompt("Show teams from:")
        .items(&TeamsOwnership::get_all_values())
        .default(0)
        .interact();

    let select_error = "Failed to read user's choice.";

    let ownership = match from_team {
        Ok(index) => match index {
            0 => TeamsOwnership::MyTeams,
            1 => TeamsOwnership::SharedTeams,

            _ => {
                print_formatted_error(select_error);
                std::process::exit(1);
            }
        },

        Err(_) => {
            print_formatted_error(select_error);
            std::process::exit(1);
        }
    };

    let authorization_headers = authorization_headers(&access_token);
    let teams_error_message = "Teams not found";
    let client = Client::new();
    let user_id = fetch_user_id(&access_token);
    let mut list = Vec::new();

    match ownership {
        TeamsOwnership::MyTeams => {
            let my_teams = execute_graphql_request::<my_teams::Variables, my_teams::ResponseData>(
                authorization_headers.clone(),
                MyTeams::build_query,
                &client,
                &teams_error_message,
                my_teams::Variables { user_id },
            )
            .team;

            for team in my_teams {
                list.push(format!(
                    "{}  {}  members: {}  owner: {}",
                    &team.id.to_string()[..4].green(),
                    lengify(&team.name),
                    match &team.members_aggregate.aggregate {
                        Some(aggregate) => {
                            aggregate.count
                        }

                        None => {
                            print_formatted_error(&teams_error_message);
                            std::process::exit(1);
                        }
                    },
                    match &team.owner {
                        Some(owner) => {
                            &owner.name
                        }

                        None => {
                            print_formatted_error(&teams_error_message);
                            std::process::exit(1);
                        }
                    }
                ))
            }
        }

        TeamsOwnership::SharedTeams => {
            let shared_teams =
                execute_graphql_request::<shared_teams::Variables, shared_teams::ResponseData>(
                    authorization_headers.clone(),
                    SharedTeams::build_query,
                    &client,
                    &teams_error_message,
                    shared_teams::Variables { user_id },
                )
                .team;

            for team in shared_teams {
                list.push(format!(
                    "{}  {}  members: {}  owner: {}",
                    &team.id.to_string()[..4].green(),
                    lengify(&team.name),
                    match &team.members_aggregate.aggregate {
                        Some(aggregate) => {
                            aggregate.count
                        }

                        None => {
                            print_formatted_error(&teams_error_message);
                            std::process::exit(1);
                        }
                    },
                    match &team.owner {
                        Some(owner) => {
                            &owner.name
                        }

                        None => {
                            print_formatted_error(&teams_error_message);
                            std::process::exit(1);
                        }
                    }
                ))
            }
        }
    }

    pagination_list(
        list,
        format!(
            "{} teams:",
            match ownership {
                TeamsOwnership::MyTeams => "My",
                TeamsOwnership::SharedTeams => "Shared",
            }
        ),
        "No teams found.",
    )
}