async registration working
This commit is contained in:
@@ -45,6 +45,7 @@ use crate::config::binds::key_sequences::KeySequenceTracker;
|
||||
use tokio::spawn;
|
||||
use tokio::sync::mpsc;
|
||||
use crate::tui::functions::common::login::LoginResult;
|
||||
use crate::tui::functions::common::register::RegisterResult;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum EventOutcome {
|
||||
@@ -65,10 +66,14 @@ pub struct EventHandler {
|
||||
pub key_sequence_tracker: KeySequenceTracker,
|
||||
pub auth_client: AuthClient,
|
||||
pub login_result_sender: mpsc::Sender<LoginResult>,
|
||||
pub register_result_sender: mpsc::Sender<RegisterResult>,
|
||||
}
|
||||
|
||||
impl EventHandler {
|
||||
pub async fn new(login_result_sender: mpsc::Sender<LoginResult>) -> Result<Self> {
|
||||
pub async fn new(
|
||||
login_result_sender: mpsc::Sender<LoginResult>,
|
||||
register_result_sender: mpsc::Sender<RegisterResult>,
|
||||
) -> Result<Self> {
|
||||
Ok(EventHandler {
|
||||
command_mode: false,
|
||||
command_input: String::new(),
|
||||
@@ -80,6 +85,7 @@ impl EventHandler {
|
||||
key_sequence_tracker: KeySequenceTracker::new(800),
|
||||
auth_client: AuthClient::new().await?,
|
||||
login_result_sender,
|
||||
register_result_sender,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -279,11 +285,56 @@ impl EventHandler {
|
||||
login_action_message
|
||||
}
|
||||
UiContext::Register => {
|
||||
match index {
|
||||
0 => register::save(register_state, &mut self.auth_client, app_state).await.context("Register save action failed")?,
|
||||
let register_action_message = match index {
|
||||
0 => { // "Register" button pressed
|
||||
// Clone necessary data
|
||||
let username = register_state.username.clone();
|
||||
let email = register_state.email.clone();
|
||||
let password = register_state.password.clone();
|
||||
let password_confirmation = register_state.password_confirmation.clone();
|
||||
let role = register_state.role.clone();
|
||||
|
||||
// 1. Client-side validation (similar to register::save)
|
||||
if username.trim().is_empty() {
|
||||
app_state.show_dialog("Registration Failed", "Username cannot be empty.", vec!["OK".to_string()], DialogPurpose::RegisterFailed);
|
||||
"Username cannot be empty.".to_string()
|
||||
} else if !password.is_empty() && password != password_confirmation {
|
||||
app_state.show_dialog("Registration Failed", "Passwords do not match.", vec!["OK".to_string()], DialogPurpose::RegisterFailed);
|
||||
"Passwords do not match.".to_string()
|
||||
} else {
|
||||
// 2. Show Loading Dialog
|
||||
app_state.show_loading_dialog("Registering", "Please wait...");
|
||||
|
||||
// 3. Clone sender for the task
|
||||
let sender = self.register_result_sender.clone();
|
||||
|
||||
// 4. Spawn the registration task
|
||||
spawn(async move {
|
||||
let register_outcome = match AuthClient::new().await {
|
||||
Ok(mut auth_client) => {
|
||||
// Handle optional fields correctly for the gRPC call
|
||||
let password_opt = if password.is_empty() { None } else { Some(password) };
|
||||
let password_conf_opt = if password_confirmation.is_empty() { None } else { Some(password_confirmation) };
|
||||
let role_opt = if role.is_empty() { None } else { Some(role) };
|
||||
|
||||
match auth_client.register(username.clone(), email, password_opt, password_conf_opt, role_opt).await {
|
||||
Ok(response) => register::RegisterResult::Success(response),
|
||||
Err(e) => register::RegisterResult::Failure(format!("{}", e)),
|
||||
}
|
||||
}
|
||||
Err(e) => register::RegisterResult::ConnectionError(format!("Failed to create AuthClient: {}", e)),
|
||||
};
|
||||
let _ = sender.send(register_outcome).await;
|
||||
});
|
||||
|
||||
// 5. Return immediately
|
||||
"Registration initiated.".to_string()
|
||||
}
|
||||
},
|
||||
1 => register::back_to_login(register_state, app_state, buffer_state).await,
|
||||
_ => "Invalid Login Option".to_string(),
|
||||
}
|
||||
};
|
||||
register_action_message
|
||||
}
|
||||
UiContext::Admin => {
|
||||
admin::handle_admin_selection(app_state, admin_state);
|
||||
|
||||
@@ -8,8 +8,16 @@ use crate::state::{
|
||||
};
|
||||
use crate::ui::handlers::context::DialogPurpose;
|
||||
use crate::state::app::buffer::{AppView, BufferState};
|
||||
use common::proto::multieko2::auth::AuthResponse;
|
||||
use anyhow::Result;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum RegisterResult {
|
||||
Success(AuthResponse),
|
||||
Failure(String),
|
||||
ConnectionError(String),
|
||||
}
|
||||
|
||||
/// Attempts to register the user using the provided details via gRPC.
|
||||
/// Updates RegisterState and AppState on success or failure.
|
||||
pub async fn save(
|
||||
|
||||
@@ -22,6 +22,7 @@ use crate::ui::handlers::context::DialogPurpose;
|
||||
use crate::tui::terminal::{EventReader, TerminalCore};
|
||||
use crate::ui::handlers::render::render_ui;
|
||||
use crate::tui::functions::common::login::LoginResult;
|
||||
use crate::tui::functions::common::register::RegisterResult;
|
||||
use std::time::Instant;
|
||||
use anyhow::{Context, Result};
|
||||
use crossterm::cursor::SetCursorStyle;
|
||||
@@ -39,7 +40,12 @@ pub async fn run_ui() -> Result<()> {
|
||||
// --- Channel for Login Results ---
|
||||
let (login_result_sender, mut login_result_receiver) =
|
||||
mpsc::channel::<LoginResult>(1);
|
||||
let mut event_handler = EventHandler::new(login_result_sender.clone()).await.context("Failed to create event handler")?;
|
||||
let (register_result_sender, mut register_result_receiver) =
|
||||
mpsc::channel::<RegisterResult>(1);
|
||||
let mut event_handler = EventHandler::new(
|
||||
login_result_sender.clone(),
|
||||
register_result_sender.clone(),
|
||||
).await.context("Failed to create event handler")?;
|
||||
let event_reader = EventReader::new();
|
||||
|
||||
let mut auth_state = AuthState::default();
|
||||
@@ -241,6 +247,52 @@ pub async fn run_ui() -> Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
// --- Check for Register Results from Channel ---
|
||||
match register_result_receiver.try_recv() {
|
||||
Ok(register_result) => {
|
||||
// A result arrived from the register task!
|
||||
match register_result {
|
||||
RegisterResult::Success(response) => {
|
||||
// Update Dialog
|
||||
let success_message = format!(
|
||||
"Registration Successful!\n\nUser ID: {}\nUsername: {}\nEmail: {}\nRole: {}",
|
||||
response.id, response.username, response.email, response.role
|
||||
);
|
||||
app_state.update_dialog_content( // Update loading dialog
|
||||
&success_message,
|
||||
vec!["OK".to_string()], // Simple OK for now
|
||||
DialogPurpose::RegisterSuccess,
|
||||
);
|
||||
info!(message = %success_message, "Registration successful");
|
||||
}
|
||||
RegisterResult::Failure(err_msg) => {
|
||||
app_state.update_dialog_content( // Update loading dialog
|
||||
&err_msg,
|
||||
vec!["OK".to_string()],
|
||||
DialogPurpose::RegisterFailed,
|
||||
);
|
||||
register_state.error_message = Some(err_msg.clone()); // Keep error message
|
||||
error!(error = %err_msg, "Registration failed");
|
||||
}
|
||||
RegisterResult::ConnectionError(err_msg) => {
|
||||
app_state.update_dialog_content( // Update loading dialog
|
||||
&err_msg, // Show connection error
|
||||
vec!["OK".to_string()],
|
||||
DialogPurpose::RegisterFailed, // Still a failure from user perspective
|
||||
);
|
||||
register_state.error_message = Some(err_msg.clone());
|
||||
error!(error = %err_msg, "Registration connection error");
|
||||
}
|
||||
}
|
||||
register_state.set_has_unsaved_changes(false); // Clear unsaved changes flag after processing
|
||||
needs_redraw = true; // Set flag: Register result processed, UI state (dialog) changed
|
||||
}
|
||||
Err(mpsc::error::TryRecvError::Empty) => { /* No message waiting */ }
|
||||
Err(mpsc::error::TryRecvError::Disconnected) => {
|
||||
error!("Register result channel disconnected unexpectedly.");
|
||||
}
|
||||
}
|
||||
|
||||
// --- Centralized Consequence Handling ---
|
||||
let mut should_exit = false;
|
||||
match event_outcome_result {
|
||||
|
||||
Reference in New Issue
Block a user