use anyhow::{Context, Result};
use std::io::{self, Write};
use super::oauth;
use super::token::TokenStore;
use crate::config::Config;
const API_KEY_SETTINGS_URL: &str = "https://linear.app/settings/account/security";
pub async fn run(token_store: &TokenStore) -> Result<bool> {
println!("linear-tui is not connected to Linear yet.");
println!();
println!(" 1 Log in through your browser (recommended)");
println!(" 2 Paste a personal API key");
println!(" q Quit");
println!();
loop {
match prompt("Choose 1, 2 or q: ")?.as_str() {
"1" | "" => {
browser_login(token_store).await?;
return Ok(true);
}
"2" => return api_key_login().await,
"q" | "quit" => {
println!("Nothing was saved.");
return Ok(false);
}
other => println!("'{other}' is not one of the options."),
}
}
}
async fn browser_login(token_store: &TokenStore) -> Result<()> {
oauth::login(token_store).await?;
let viewer = super::identify(&super::AuthMethod::OAuth {
access_token: token_store
.load()?
.context("Login finished but no token was stored")?
.access_token,
})
.await?;
println!("Signed in as {}.", viewer.name);
Ok(())
}
async fn api_key_login() -> Result<bool> {
println!();
println!("Create a key under Settings > Account > Security & access:");
println!(" {API_KEY_SETTINGS_URL}");
if open::that(API_KEY_SETTINGS_URL).is_ok() {
println!("(opened in your browser)");
}
println!();
loop {
let key = prompt("Paste your API key (or q to quit): ")?;
if key == "q" {
println!("Nothing was saved.");
return Ok(false);
}
if key.is_empty() {
continue;
}
match save_api_key(&key).await {
Ok(name) => {
println!("Signed in as {name}.");
return Ok(true);
}
Err(e) => println!("That key did not work: {e}"),
}
}
}
pub async fn save_api_key(key: &str) -> Result<String> {
let viewer = super::identify(&super::AuthMethod::ApiKey(key.to_string())).await?;
let mut config = Config::load()?;
config.auth.api_key = Some(key.to_string());
config.save()?;
Ok(viewer.name)
}
fn prompt(label: &str) -> Result<String> {
print!("{label}");
io::stdout().flush()?;
let mut line = String::new();
if io::stdin().read_line(&mut line)? == 0 {
anyhow::bail!("Setup cancelled — no input available.");
}
Ok(line.trim().to_string())
}