use crate::handle_operation_error;
use dialoguer::{Input, Password, Select};
use sindri::{client::SindriClient, TeamDetail};
pub fn login(
client: &SindriClient,
username: Option<String>,
password: Option<String>,
keyname: Option<String>,
teamname: Option<String>,
) {
println!("{}", console::style("Logging in...").bold());
let username = match username {
Some(u) => u,
None => Input::new()
.with_prompt(" Username")
.interact_text()
.unwrap_or_else(|e| handle_operation_error("Login", &e.to_string())),
};
let password = match password {
Some(p) => p,
None => Password::new()
.with_prompt(" Password")
.interact()
.unwrap_or_else(|e| handle_operation_error("Login", &e.to_string())),
};
let name = match keyname {
Some(n) => {
if n.len() > 32 {
handle_operation_error("Login", "API key name must not exceed 32 characters.");
}
n
}
None => Input::new()
.with_prompt(" New API Key Name")
.with_initial_text(format!("{}-rust-sdk", username))
.validate_with(|input: &String| -> Result<(), String> {
if input.len() > 32 {
Err("API key name must not exceed 32 characters.".to_string())
} else {
Ok(())
}
})
.interact_text()
.unwrap_or_else(|e| handle_operation_error("Login", &e.to_string())),
};
let rt = tokio::runtime::Runtime::new().unwrap();
let token = match rt.block_on(client.jwt_token_generate(&username, &password)) {
Ok(token) => token,
Err(e) => handle_operation_error("Login", &e.to_string()),
};
println!("{}", console::style(" ✓ Valid credentials").cyan());
let teams = match rt.block_on(client.teams_jwt_auth(&token)) {
Ok(teams) => teams,
Err(e) => handle_operation_error("Login", &e.to_string()),
};
if teams.is_empty() {
handle_operation_error("Login", "No teams found for this user");
}
let team_names: Vec<String> = teams.iter().map(|t: &TeamDetail| t.slug.clone()).collect();
let selected_team = match teamname {
Some(t) => {
if !team_names.contains(&t) {
handle_operation_error(
"Login",
&format!(
"Team '{}' not found. Available teams: {}",
t,
team_names.join(", ")
),
);
}
&teams[team_names.iter().position(|x| x == &t).unwrap()]
}
None => {
let selection = Select::new()
.with_prompt(" Select a team to generate an API key for")
.items(&team_names)
.interact()
.unwrap_or_else(|e| handle_operation_error("Login", &e.to_string()));
&teams[selection]
}
};
let api_key = match rt.block_on(client.api_key_select_team(
&username,
&password,
&name,
&selected_team.id.to_string(),
)) {
Ok(key) => key,
Err(e) => handle_operation_error("Login", &e.to_string()),
};
println!(
"{}",
console::style(" ✓ API key generated successfully!").cyan()
);
println!(
"\n{}",
console::style("To authenticate future requests with the rust SDK, you can either:").bold()
);
println!(
"• Set SINDRI_API_KEY={} in your environment variables",
console::style(&api_key).cyan()
);
println!(
"• Supply --api-key={} in any `cargo sindri` command",
console::style(&api_key).cyan()
);
println!(
"\n{}",
console::style("Make sure to keep track of this key as it will only be shown once").dim()
);
}