Merge pull request 'Create global logged in user resource' (#128) from 126-create-global-logged-in-user-resource into main
Reviewed-on: LibreTunes/LibreTunes#128
This commit is contained in:
commit
186c622e6f
20
src/app.rs
20
src/app.rs
@ -3,12 +3,16 @@ use crate::playbar::CustomTitle;
|
|||||||
use crate::playstatus::PlayStatus;
|
use crate::playstatus::PlayStatus;
|
||||||
use crate::queue::Queue;
|
use crate::queue::Queue;
|
||||||
use leptos::*;
|
use leptos::*;
|
||||||
|
use leptos::logging::*;
|
||||||
use leptos_meta::*;
|
use leptos_meta::*;
|
||||||
use leptos_router::*;
|
use leptos_router::*;
|
||||||
use crate::pages::login::*;
|
use crate::pages::login::*;
|
||||||
use crate::pages::signup::*;
|
use crate::pages::signup::*;
|
||||||
use crate::error_template::{AppError, ErrorTemplate};
|
use crate::error_template::{AppError, ErrorTemplate};
|
||||||
|
use crate::auth::get_logged_in_user;
|
||||||
|
use crate::models::User;
|
||||||
|
|
||||||
|
pub type LoggedInUserResource = Resource<(), Option<User>>;
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn App() -> impl IntoView {
|
pub fn App() -> impl IntoView {
|
||||||
@ -19,6 +23,18 @@ pub fn App() -> impl IntoView {
|
|||||||
let play_status = create_rw_signal(play_status);
|
let play_status = create_rw_signal(play_status);
|
||||||
let upload_open = create_rw_signal(false);
|
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! {
|
view! {
|
||||||
// injects a stylesheet into the document <head>
|
// injects a stylesheet into the document <head>
|
||||||
// id=leptos means cargo-leptos will hot-reload this stylesheet
|
// id=leptos means cargo-leptos will hot-reload this stylesheet
|
||||||
@ -43,8 +59,8 @@ pub fn App() -> impl IntoView {
|
|||||||
<Route path="dashboard" view=Dashboard />
|
<Route path="dashboard" view=Dashboard />
|
||||||
<Route path="search" view=Search />
|
<Route path="search" view=Search />
|
||||||
</Route>
|
</Route>
|
||||||
<Route path="/login" view=Login />
|
<Route path="/login" view=move || view!{ <Login user=logged_in_user /> } />
|
||||||
<Route path="/signup" view=Signup />
|
<Route path="/signup" view=move || view!{ <Signup user=logged_in_user /> } />
|
||||||
</Routes>
|
</Routes>
|
||||||
</main>
|
</main>
|
||||||
</Router>
|
</Router>
|
||||||
|
23
src/auth.rs
23
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
|
/// Takes in a username or email and a password in plaintext
|
||||||
/// Returns a Result with a boolean indicating if the login was successful
|
/// Returns a Result with a boolean indicating if the login was successful
|
||||||
#[server(endpoint = "login")]
|
#[server(endpoint = "login")]
|
||||||
pub async fn login(credentials: UserCredentials) -> Result<bool, ServerFnError> {
|
pub async fn login(credentials: UserCredentials) -> Result<Option<User>, ServerFnError> {
|
||||||
use crate::users::validate_user;
|
use crate::users::validate_user;
|
||||||
|
|
||||||
let mut auth_session = extract::<AuthSession<AuthBackend>>().await
|
let mut auth_session = extract::<AuthSession<AuthBackend>>().await
|
||||||
@ -66,12 +66,14 @@ pub async fn login(credentials: UserCredentials) -> Result<bool, ServerFnError>
|
|||||||
let user = validate_user(credentials).await
|
let user = validate_user(credentials).await
|
||||||
.map_err(|e| ServerFnError::<NoCustomError>::ServerError(format!("Error validating user: {}", e)))?;
|
.map_err(|e| ServerFnError::<NoCustomError>::ServerError(format!("Error validating user: {}", e)))?;
|
||||||
|
|
||||||
if let Some(user) = user {
|
if let Some(mut user) = user {
|
||||||
auth_session.login(&user).await
|
auth_session.login(&user).await
|
||||||
.map_err(|e| ServerFnError::<NoCustomError>::ServerError(format!("Error logging in user: {}", e)))?;
|
.map_err(|e| ServerFnError::<NoCustomError>::ServerError(format!("Error logging in user: {}", e)))?;
|
||||||
Ok(true)
|
|
||||||
|
user.password = None;
|
||||||
|
Ok(Some(user))
|
||||||
} else {
|
} else {
|
||||||
Ok(false)
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,6 +147,19 @@ pub async fn get_user() -> Result<User, ServerFnError> {
|
|||||||
auth_session.user.ok_or(ServerFnError::<NoCustomError>::ServerError("User not logged in".to_string()))
|
auth_session.user.ok_or(ServerFnError::<NoCustomError>::ServerError("User not logged in".to_string()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[server(endpoint = "get_logged_in_user")]
|
||||||
|
pub async fn get_logged_in_user() -> Result<Option<User>, ServerFnError> {
|
||||||
|
let auth_session = extract::<AuthSession<AuthBackend>>().await
|
||||||
|
.map_err(|e| ServerFnError::<NoCustomError>::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
|
/// Check if a user is an admin
|
||||||
/// Returns a Result with a boolean indicating if the user is logged in and an admin
|
/// Returns a Result with a boolean indicating if the user is logged in and an admin
|
||||||
#[server(endpoint = "check_admin")]
|
#[server(endpoint = "check_admin")]
|
||||||
|
@ -3,9 +3,10 @@ use leptos::leptos_dom::*;
|
|||||||
use leptos::*;
|
use leptos::*;
|
||||||
use leptos_icons::*;
|
use leptos_icons::*;
|
||||||
use crate::users::UserCredentials;
|
use crate::users::UserCredentials;
|
||||||
|
use crate::app::LoggedInUserResource;
|
||||||
|
|
||||||
#[component]
|
#[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 (username_or_email, set_username_or_email) = create_signal("".to_string());
|
||||||
let (password, set_password) = 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 {
|
if let Err(err) = login_result {
|
||||||
// Handle the error here, e.g., log it or display to the user
|
// Handle the error here, e.g., log it or display to the user
|
||||||
log!("Error logging in: {:?}", err);
|
log!("Error logging in: {:?}", err);
|
||||||
} else if let Ok(true) = 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
|
// Redirect to the login page
|
||||||
log!("Logged in Successfully!");
|
log!("Logged in Successfully!");
|
||||||
leptos_router::use_navigate()("/", Default::default());
|
leptos_router::use_navigate()("/", Default::default());
|
||||||
log!("Navigated to home page after login");
|
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");
|
log!("Invalid username or password");
|
||||||
|
|
||||||
|
// User could be already logged in or not, so refetch the user
|
||||||
|
user.refetch();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -3,9 +3,10 @@ use crate::models::User;
|
|||||||
use leptos::leptos_dom::*;
|
use leptos::leptos_dom::*;
|
||||||
use leptos::*;
|
use leptos::*;
|
||||||
use leptos_icons::*;
|
use leptos_icons::*;
|
||||||
|
use crate::app::LoggedInUserResource;
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn Signup() -> impl IntoView {
|
pub fn Signup(user: LoggedInUserResource) -> impl IntoView {
|
||||||
let (username, set_username) = create_signal("".to_string());
|
let (username, set_username) = create_signal("".to_string());
|
||||||
let (email, set_email) = create_signal("".to_string());
|
let (email, set_email) = create_signal("".to_string());
|
||||||
let (password, set_password) = 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| {
|
let on_submit = move |ev: leptos::ev::SubmitEvent| {
|
||||||
ev.prevent_default();
|
ev.prevent_default();
|
||||||
let new_user = User {
|
let mut new_user = User {
|
||||||
id: None,
|
id: None,
|
||||||
username: username.get(),
|
username: username.get(),
|
||||||
email: email.get(),
|
email: email.get(),
|
||||||
@ -30,10 +31,17 @@ pub fn Signup() -> impl IntoView {
|
|||||||
log!("new user: {:?}", new_user);
|
log!("new user: {:?}", new_user);
|
||||||
|
|
||||||
spawn_local(async move {
|
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
|
// Handle the error here, e.g., log it or display to the user
|
||||||
log!("Error signing up: {:?}", err);
|
log!("Error signing up: {:?}", err);
|
||||||
|
|
||||||
|
// Since we're not sure what the state is, manually refetch the user
|
||||||
|
user.refetch();
|
||||||
} else {
|
} 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
|
// Redirect to the login page
|
||||||
log!("Signed up successfully!");
|
log!("Signed up successfully!");
|
||||||
leptos_router::use_navigate()("/", Default::default());
|
leptos_router::use_navigate()("/", Default::default());
|
||||||
|
Loading…
x
Reference in New Issue
Block a user