zero-cli 1.0.1

A command line tool for Zero Secrets Manager
pub mod graphql;
use crate::common::{
    authorization_headers::authorization_headers,
    execute_graphql_request::execute_graphql_request,
    fetch_user_id::fetch_user_id,
    format_relative_time::format_relative_time,
    keyring::keyring,
    lengify::lengify,
    pagination_list::pagination_list,
    print_formatted_error::print_formatted_error,
    query_full_id::{query_full_id, QueryType},
};
use crate::projects::list::graphql::team_projects::{team_projects, TeamProjects};
use crate::projects::list::graphql::user_personal_project_team_id::{
    user_personal_project_team_id, UserPersonalProjectTeamId,
};
use clap::Args;
use graphql_client::GraphQLQuery;
use reqwest::Client;
use termimad::crossterm::style::Stylize;

#[derive(Args, Debug)]
pub struct ProjectsListArgs {
    #[clap(
        short,
        long,
        help = "Team ID (First 4 characters or more are allowed), not required"
    )]
    id: Option<String>,
    #[clap(
        short,
        long,
        help = "Access token, if not specified, the token will be taken from the keychain"
    )]
    access_token: Option<String>,
}

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

    let client = Client::new();
    let authorization_headers = authorization_headers(&access_token);
    let user_id = fetch_user_id(&access_token);
    let team_id;
    let mut is_personal_project = false;

    match &args.id {
        Some(id) => {
            team_id = query_full_id(QueryType::Teams, id.clone(), &access_token);
        }

        None => {
            let user_personal_project_team_id_error_message = "Personal projects not found";

            let personal_team = execute_graphql_request::<
                user_personal_project_team_id::Variables,
                user_personal_project_team_id::ResponseData,
            >(
                authorization_headers.clone(),
                UserPersonalProjectTeamId::build_query,
                &client,
                &user_personal_project_team_id_error_message,
                user_personal_project_team_id::Variables {
                    user_id: user_id.clone(),
                },
            )
            .team;

            if let Some(team_data) = personal_team.first() {
                team_id = team_data.id.clone();
                is_personal_project = true;
            } else {
                print_formatted_error(&user_personal_project_team_id_error_message);
                std::process::exit(1);
            }
        }
    }

    let projects: Vec<team_projects::TeamProjectsToken> =
        execute_graphql_request::<team_projects::Variables, team_projects::ResponseData>(
            authorization_headers.clone(),
            TeamProjects::build_query,
            &client,
            &format!("Projects for team '{}' not found.", &team_id),
            team_projects::Variables {
                id: team_id,
                user_id,
            },
        )
        .token;

    let mut list = Vec::new();

    for project in projects {
        let last_usage_time = if let Some(usage_history) = project.usage_history.first() {
            match format_relative_time(&usage_history.updated_at.to_string()) {
                Ok(relative_time) => relative_time,

                Err(_) => {
                    print_formatted_error("Failed to format last data usage time.");
                    std::process::exit(1);
                }
            }
        } else {
            "never used".to_string().grey()
        };

        list.push(format!(
            "{}  {}  {}  {}",
            &project.id.to_string()[..4].green(),
            lengify(&project.name),
            if is_personal_project {
                "".to_string()
            } else {
                format!(
                    "{} ({})",
                    project.owner.name.dark_cyan(),
                    project.owner.email.dark_cyan()
                )
            },
            last_usage_time.dark_grey()
        ))
    }

    pagination_list(
        list,
        format!(
            "Showing projects in {} team",
            &team_id.to_string().bold().dark_cyan()
        ),
        "You don't have any projects on this team.",
    )
}