Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 4 additions & 16 deletions src/api/auth.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,6 @@
use crate::api::client::{ApiClient, Endpoint};
use keyring::KeyringEntry;
use serde::Deserialize;

#[derive(Deserialize)]
pub struct UserInfo {
pub username: String,
pub display_name: Option<String>,
}

impl UserInfo {
/// Returns the display name if set, otherwise falls back to the username.
pub fn name(&self) -> &str {
self.display_name.as_deref().unwrap_or(&self.username)
}
}
use serde_json::Value;

pub struct Auth {
pub token_entry: KeyringEntry,
Expand All @@ -35,12 +22,13 @@ impl Auth {
})
}

pub async fn validate_token(&self, token: &str) -> Result<UserInfo, String> {
pub async fn validate_token(&self, token: &str) -> Result<ApiClient, String> {
let client = ApiClient::new(token.to_string());

client
.get::<UserInfo>(Endpoint::CurrentUser)
.get::<Value>(Endpoint::CurrentUser)
.await
.map(|_| client)
.map_err(|e| {
let err_msg = e.to_string();
if err_msg.contains("401") {
Expand Down
15 changes: 8 additions & 7 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use ratatui::crossterm::event::{KeyCode, KeyEvent};

use crate::action::Action;
use crate::api::auth::Auth;
use crate::api::client::ApiClient;
use crate::input::InputState;
use crate::{Result, cache::CacheStore};

Expand All @@ -16,9 +17,9 @@ pub struct App {
pub state: AppState,
pub input_text: String,
pub auth: Auth,
pub username: String,
pub should_quit: bool,
pub input_state: InputState,
pub client: ApiClient,
#[allow(unused)]
pub cache: CacheStore,
}
Expand All @@ -27,12 +28,12 @@ impl App {
pub async fn new() -> Result<Self> {
let auth = Auth::new().map_err(|e| anyhow::anyhow!(e))?;

let mut username = String::new();
let mut client = ApiClient::new(String::new());

let state = if let Ok(token) = auth.token_entry.get_secret().await {
match auth.validate_token(&token).await {
Ok(user_info) => {
username = user_info.name().to_string();
Ok(authenticated_client) => {
client = authenticated_client;
AppState::LoggedIn
}
Err(e) => AppState::Error(format!("Stored token is invalid: {}", e)),
Expand All @@ -47,8 +48,8 @@ impl App {
state,
input_text: String::new(),
auth,
username,
should_quit: false,
client,
cache,
input_state: InputState::default(),
})
Expand All @@ -61,9 +62,9 @@ impl App {
if !self.input_text.is_empty() {
self.state = AppState::ValidatingToken;
match self.auth.validate_token(&self.input_text).await {
Ok(user_info) => match self.auth.store_token(&self.input_text).await {
Ok(client) => match self.auth.store_token(&self.input_text).await {
Ok(_) => {
self.username = user_info.name().to_string();
self.client = client;
self.state = AppState::LoggedIn;
}
Err(detailed_err) => {
Expand Down
3 changes: 1 addition & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,12 @@ mod app;
mod cache;
mod error;
mod input;
mod state;
mod ui;

use std::{fs, path::PathBuf};

use app::App;
use ratatui::crossterm::event::{self, Event};
use state::ui;

pub const LOG_FILE: &str = "logs";

Expand Down
1 change: 0 additions & 1 deletion src/state/mod.rs

This file was deleted.

67 changes: 0 additions & 67 deletions src/state/ui.rs

This file was deleted.

17 changes: 17 additions & 0 deletions src/ui/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
use ratatui::{
Frame,
style::{Color, Style},
widgets::{Block, Borders, Paragraph},
};

pub fn render(f: &mut Frame, message: &str) {
let error_text = format!("CRITICAL SYSTEM ERROR:\n\n{message}\n\nPress any key to return...");
let error_msg = Paragraph::new(error_text)
.style(Style::default().fg(Color::Red))
.block(
Block::default()
.title(" Keyring Failure ")
.borders(Borders::ALL),
);
f.render_widget(error_msg, f.area());
}
30 changes: 30 additions & 0 deletions src/ui/input_token.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
use crate::app::App;
use ratatui::{
Frame,
layout::{Constraint, Direction, Layout},
style::{Color, Style},
widgets::{Block, Borders, Paragraph},
};

pub fn render(f: &mut Frame, app: &App) {
let area = f.area();
let chunks = Layout::default()
.direction(Direction::Vertical)
.margin(2)
.constraints([
Constraint::Length(2),
Constraint::Length(3),
Constraint::Min(0),
])
.split(area);

let explanation = Paragraph::new(
"We couldn't find your user_token. Please paste it below and press Enter to save it securely:",
)
.style(Style::default().fg(Color::Yellow));
f.render_widget(explanation, chunks[0]);

let input_block = Paragraph::new(app.input_text.as_str())
.block(Block::default().title(" User Token ").borders(Borders::ALL));
f.render_widget(input_block, chunks[1]);
}
8 changes: 8 additions & 0 deletions src/ui/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
mod error;
mod input_token;
mod server_list;
mod validating_token;

mod render;

pub use render::render;
13 changes: 13 additions & 0 deletions src/ui/render.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use crate::app::{App, AppState};
use ratatui::Frame;

use super::{error, input_token, server_list, validating_token};

pub fn render(f: &mut Frame, app: &App) {
match &app.state {
AppState::InputToken => input_token::render(f, app),
AppState::ValidatingToken => validating_token::render(f),
AppState::LoggedIn => server_list::render(f, app),
AppState::Error(message) => error::render(f, message),
}
}
13 changes: 13 additions & 0 deletions src/ui/server_list.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use crate::app::App;
use ratatui::{
Frame,
style::{Color, Style},
widgets::{Block, Borders, Paragraph},
};

pub fn render(f: &mut Frame, _app: &App) {
let msg = Paragraph::new("Server list is not yet implemented.")
.style(Style::default().fg(Color::Yellow))
.block(Block::default().title(" Servers ").borders(Borders::ALL));
f.render_widget(msg, f.area());
}
16 changes: 16 additions & 0 deletions src/ui/validating_token.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
use ratatui::{
Frame,
style::{Color, Style},
widgets::{Block, Borders, Paragraph},
};

pub fn render(f: &mut Frame) {
let msg = Paragraph::new("Validating token with Stoat API...")
.style(Style::default().fg(Color::Cyan))
.block(
Block::default()
.title(" Authenticating ")
.borders(Borders::ALL),
);
f.render_widget(msg, f.area());
}