use super::prompt::{prompt_if_missing, prompt_if_missing_password};
use super::state::ChrsSessions;
use super::store;
use crate::credentials::Credentials;
use chris::{
types::{CubeUrl, Username},
Account, AnonChrisClient, ChrisClient,
};
use color_eyre::eyre::{bail, Context, Result};
use color_eyre::owo_colors::OwoColorize;
pub async fn login(
Credentials {
cube_url,
username,
password,
token,
ui,
config_path,
..
}: Credentials,
backend: store::Backend,
password_from_stdin: bool,
) -> Result<()> {
if password.is_some() && password_from_stdin {
bail!(
"Options {} and {} may not be used together.",
"--password".bold(),
"--password-stdin".bold()
);
}
let mut config = ChrsSessions::load(config_path.as_deref())?;
let cube = prompt_if_missing(cube_url, "ChRIS API address")?;
let username = prompt_if_missing(username, "username")?;
let token = if username.as_str().is_empty() {
login_anonymous(&cube).await
} else if let Some(token) = token {
login_with_token(&cube, &username, &token).await
} else {
let password = prompt_if_missing_password(password, "password", password_from_stdin)?;
login_with_password(&cube, &username, &password).await
}?;
let login = store::CubeState {
cube,
token,
username,
current_plugin_instance_id: None,
ui,
};
config.add(login, backend)?;
config.save(config_path.as_deref())
}
async fn login_anonymous(cube_url: &CubeUrl) -> Result<Option<String>> {
AnonChrisClient::build(cube_url.clone())?.connect().await?;
Ok(None)
}
async fn login_with_password(
cube_url: &CubeUrl,
username: &Username,
password: &str,
) -> Result<Option<String>> {
let account = Account {
client: Default::default(),
url: cube_url,
username,
password,
};
let token = account.get_token().await.wrap_err("Could not log in")?;
Ok(Some(token))
}
async fn login_with_token(
cube_url: &CubeUrl,
username: &Username,
token: &str,
) -> Result<Option<String>> {
ChrisClient::build(cube_url.clone(), username.clone(), token)?
.connect()
.await
.wrap_err_with(|| format!("Invalid token for {cube_url}"))?;
Ok(Some(token.to_string()))
}
pub fn logout(
Credentials {
cube_url,
username,
config_path,
..
}: Credentials,
) -> Result<()> {
let mut config = ChrsSessions::load(config_path.as_deref())?;
if let Some(url) = cube_url {
let removed = match username {
Some(u) => config.remove(&url, Some(&u)),
None => config.remove(&url, None),
};
if !removed {
bail!("Not logged in.");
}
} else if !config.clear() {
bail!("Not logged in.");
}
config.save(config_path.as_deref())
}