From 251d56786399a7fe50d77219ab41a0f2afd3d605 Mon Sep 17 00:00:00 2001 From: Ethan Girouard Date: Sun, 3 Nov 2024 16:52:15 -0500 Subject: [PATCH 1/4] Return logged in user from login endpoint --- src/auth.rs | 10 ++++++---- src/pages/login.rs | 4 ++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/auth.rs b/src/auth.rs index 37f861f..c0751d1 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -57,7 +57,7 @@ pub async fn signup(new_user: User) -> Result<(), ServerFnError> { /// Takes in a username or email and a password in plaintext /// Returns a Result with a boolean indicating if the login was successful #[server(endpoint = "login")] -pub async fn login(credentials: UserCredentials) -> Result { +pub async fn login(credentials: UserCredentials) -> Result, ServerFnError> { use crate::users::validate_user; let mut auth_session = extract::>().await @@ -66,12 +66,14 @@ pub async fn login(credentials: UserCredentials) -> Result let user = validate_user(credentials).await .map_err(|e| ServerFnError::::ServerError(format!("Error validating user: {}", e)))?; - if let Some(user) = user { + if let Some(mut user) = user { auth_session.login(&user).await .map_err(|e| ServerFnError::::ServerError(format!("Error logging in user: {}", e)))?; - Ok(true) + + user.password = None; + Ok(Some(user)) } else { - Ok(false) + Ok(None) } } diff --git a/src/pages/login.rs b/src/pages/login.rs index 62aca49..1fda5ca 100644 --- a/src/pages/login.rs +++ b/src/pages/login.rs @@ -32,12 +32,12 @@ pub fn Login() -> impl IntoView { if let Err(err) = login_result { // Handle the error here, e.g., log it or display to the user log!("Error logging in: {:?}", err); - } else if let Ok(true) = login_result { + } else if let Ok(Some(_)) = login_result { // Redirect to the login page log!("Logged in Successfully!"); leptos_router::use_navigate()("/", Default::default()); log!("Navigated to home page after login"); - } else if let Ok(false) = login_result { + } else if let Ok(None) = login_result { log!("Invalid username or password"); } }); From 43a5b519fdf8e5fb744db287d907bf59bdc5e23f Mon Sep 17 00:00:00 2001 From: Ethan Girouard Date: Sun, 3 Nov 2024 16:59:23 -0500 Subject: [PATCH 2/4] Add API endpoint to get logged in user --- src/auth.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/auth.rs b/src/auth.rs index c0751d1..558bfe2 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -147,6 +147,19 @@ pub async fn get_user() -> Result { auth_session.user.ok_or(ServerFnError::::ServerError("User not logged in".to_string())) } +#[server(endpoint = "get_logged_in_user")] +pub async fn get_logged_in_user() -> Result, ServerFnError> { + let auth_session = extract::>().await + .map_err(|e| ServerFnError::::ServerError(format!("Error getting auth session: {}", e)))?; + + let user = auth_session.user.map(|mut user| { + user.password = None; + user + }); + + Ok(user) +} + /// Check if a user is an admin /// Returns a Result with a boolean indicating if the user is logged in and an admin #[server(endpoint = "check_admin")] From 8ac3a87c58a2e1512e4e7ec017341713e5d0dac1 Mon Sep 17 00:00:00 2001 From: Ethan Girouard Date: Sun, 3 Nov 2024 16:59:46 -0500 Subject: [PATCH 3/4] Add global logged in user Resource --- src/app.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/app.rs b/src/app.rs index ed9fd1b..9e91878 100644 --- a/src/app.rs +++ b/src/app.rs @@ -3,12 +3,16 @@ use crate::playbar::CustomTitle; use crate::playstatus::PlayStatus; use crate::queue::Queue; use leptos::*; +use leptos::logging::*; use leptos_meta::*; use leptos_router::*; use crate::pages::login::*; use crate::pages::signup::*; use crate::error_template::{AppError, ErrorTemplate}; +use crate::auth::get_logged_in_user; +use crate::models::User; +pub type LoggedInUserResource = Resource<(), Option>; #[component] pub fn App() -> impl IntoView { @@ -19,6 +23,18 @@ pub fn App() -> impl IntoView { let play_status = create_rw_signal(play_status); let upload_open = create_rw_signal(false); + // A resource that fetches the logged in user + // This will not automatically refetch, so any login/logout related code + // should call `refetch` on this resource + let logged_in_user: LoggedInUserResource = create_resource(|| (), |_| async { + get_logged_in_user().await + .inspect_err(|e| { + error!("Error getting logged in user: {:?}", e); + }) + .ok() + .flatten() + }); + view! { // injects a stylesheet into the document // id=leptos means cargo-leptos will hot-reload this stylesheet From 2b380d77876cd7aef245a4ab1e2e5cf26b70ae9c Mon Sep 17 00:00:00 2001 From: Ethan Girouard Date: Sun, 3 Nov 2024 17:13:40 -0500 Subject: [PATCH 4/4] Refetch logged in user on login/signup --- src/app.rs | 4 ++-- src/pages/login.rs | 14 ++++++++++++-- src/pages/signup.rs | 14 +++++++++++--- 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/app.rs b/src/app.rs index 9e91878..50cad40 100644 --- a/src/app.rs +++ b/src/app.rs @@ -59,8 +59,8 @@ pub fn App() -> impl IntoView { - - + } /> + } /> diff --git a/src/pages/login.rs b/src/pages/login.rs index 1fda5ca..585f2f0 100644 --- a/src/pages/login.rs +++ b/src/pages/login.rs @@ -3,9 +3,10 @@ use leptos::leptos_dom::*; use leptos::*; use leptos_icons::*; use crate::users::UserCredentials; +use crate::app::LoggedInUserResource; #[component] -pub fn Login() -> impl IntoView { +pub fn Login(user: LoggedInUserResource) -> impl IntoView { let (username_or_email, set_username_or_email) = create_signal("".to_string()); let (password, set_password) = create_signal("".to_string()); @@ -32,13 +33,22 @@ pub fn Login() -> impl IntoView { if let Err(err) = login_result { // Handle the error here, e.g., log it or display to the user log!("Error logging in: {:?}", err); - } else if let Ok(Some(_)) = login_result { + + // Since we're not sure what the state is, manually refetch the user + user.refetch(); + } else if let Ok(Some(login_user)) = login_result { + // Manually set the user to the new user, avoiding a refetch + user.set(Some(login_user)); + // Redirect to the login page log!("Logged in Successfully!"); leptos_router::use_navigate()("/", Default::default()); log!("Navigated to home page after login"); } else if let Ok(None) = login_result { log!("Invalid username or password"); + + // User could be already logged in or not, so refetch the user + user.refetch(); } }); }; diff --git a/src/pages/signup.rs b/src/pages/signup.rs index f02dfab..8e9a0ac 100644 --- a/src/pages/signup.rs +++ b/src/pages/signup.rs @@ -3,9 +3,10 @@ use crate::models::User; use leptos::leptos_dom::*; use leptos::*; use leptos_icons::*; +use crate::app::LoggedInUserResource; #[component] -pub fn Signup() -> impl IntoView { +pub fn Signup(user: LoggedInUserResource) -> impl IntoView { let (username, set_username) = create_signal("".to_string()); let (email, set_email) = create_signal("".to_string()); let (password, set_password) = create_signal("".to_string()); @@ -19,7 +20,7 @@ pub fn Signup() -> impl IntoView { let on_submit = move |ev: leptos::ev::SubmitEvent| { ev.prevent_default(); - let new_user = User { + let mut new_user = User { id: None, username: username.get(), email: email.get(), @@ -30,10 +31,17 @@ pub fn Signup() -> impl IntoView { log!("new user: {:?}", new_user); spawn_local(async move { - if let Err(err) = signup(new_user).await { + if let Err(err) = signup(new_user.clone()).await { // Handle the error here, e.g., log it or display to the user log!("Error signing up: {:?}", err); + + // Since we're not sure what the state is, manually refetch the user + user.refetch(); } else { + // Manually set the user to the new user, avoiding a refetch + new_user.password = None; + user.set(Some(new_user)); + // Redirect to the login page log!("Signed up successfully!"); leptos_router::use_navigate()("/", Default::default());