User Authentication and Other fixes #1

Merged
vinod merged 30 commits from user-auth into main 2023-02-05 09:01:08 +00:00
3 changed files with 145 additions and 26 deletions
Showing only changes of commit aa1172bbc0 - Show all commits

View File

@@ -254,6 +254,7 @@ pub async fn main() {
.route("/api/create", post(create_book)) .route("/api/create", post(create_book))
.route("/api/update", post(update_book)) .route("/api/update", post(update_book))
.route("/api/delete/:id", get(delete_book)) .route("/api/delete/:id", get(delete_book))
.route("/api/authentication_check", get(authentication_check))
.route_layer(RequireAuthorizationLayer::<booksman_orm::AxumUser>::login()) .route_layer(RequireAuthorizationLayer::<booksman_orm::AxumUser>::login())
.route("/api/list", get(list_book)) .route("/api/list", get(list_book))
.route("/api/list_search", get(list_search_book)) .route("/api/list_search", get(list_search_book))
@@ -346,6 +347,12 @@ async fn list_users(
auth.logout().await; auth.logout().await;
} }
//https://openlibrary.org/api/books?bibkeys=ISBN:9780980200447&jscmd=data&format=json
async fn authentication_check(
Extension(user): Extension<booksman_orm::AxumUser>,
) -> impl IntoResponse {
return true;
}
//https://openlibrary.org/api/books?bibkeys=ISBN:9780980200447&jscmd=data&format=json //https://openlibrary.org/api/books?bibkeys=ISBN:9780980200447&jscmd=data&format=json

View File

@@ -37,6 +37,15 @@ body {
background-color: #f1f1f1; /* Fallback color */ background-color: #f1f1f1; /* Fallback color */
} }
/* Dropdown Content (Hidden by Default) */
.dropdown-content {
position: absolute;
background-color: #f1f1f1;
min-width: 160px;
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
z-index: 1;
}
/* Float three header columns side by side */ /* Float three header columns side by side */
.header { .header {
position: fixed; /* Stay in place */ position: fixed; /* Stay in place */

View File

@@ -13,6 +13,7 @@ use web_sys::{Event, HtmlInputElement, KeyboardEvent}; // 0.3.5
use dotenv_codegen::dotenv; use dotenv_codegen::dotenv;
use itertools::Itertools; use itertools::Itertools;
use std::collections::HashMap; use std::collections::HashMap;
use wasm_bindgen::closure::Closure;
//use gloo_timers::future::TimeoutFuture; //use gloo_timers::future::TimeoutFuture;
//#[macro_use] //#[macro_use]
//extern crate dotenv_codegen; //extern crate dotenv_codegen;
@@ -90,23 +91,9 @@ pub struct AppState {
pub loggedin: RcSignal<bool>, pub loggedin: RcSignal<bool>,
pub editmode: RcSignal<bool>, pub editmode: RcSignal<bool>,
pub dropdownselect: RcSignal<bool>, pub dropdownselect: RcSignal<bool>,
pub scrolling: RcSignal<bool>,
} }
/* TODO
let callback: Closure<dyn FnMut()> = Closure::new(move || {
info!("Got scroll event");
});
let window = web_sys::window().expect("Failed to get window");
window
.add_event_listener_with_callback_and_bool(
"scroll",
callback.as_ref().unchecked_ref(),
false, // Changing this to true does not help :/
)
.expect("Failed to set listener");
callback.forget();*/
async fn login_user(user: AxumUser) -> Result<reqwasm::http::Response, reqwasm::Error> { async fn login_user(user: AxumUser) -> Result<reqwasm::http::Response, reqwasm::Error> {
let backend_url : &'static str = dotenv!("BACKEND_URL"); let backend_url : &'static str = dotenv!("BACKEND_URL");
let url = format!("{}/api/login", backend_url); let url = format!("{}/api/login", backend_url);
@@ -140,6 +127,19 @@ async fn list_users() -> Result<HashMap<String,i32>, reqwasm::Error> {
Ok(res) Ok(res)
} }
async fn authentication_check() -> Result<bool, reqwasm::Error> {
let backend_url : &'static str = dotenv!("BACKEND_URL");
let url = format!("{}/api/authentication_check", backend_url);
let resp = Request::get(&url).send().await?;
if resp.status() == 200 {
Ok(true)
} else {
Ok(false)
}
}
async fn fetch_books(search: String) -> Result<Vec<BookUI>, reqwasm::Error> { async fn fetch_books(search: String) -> Result<Vec<BookUI>, reqwasm::Error> {
//dotenvy::dotenv().ok(); //dotenvy::dotenv().ok();
let backend_url : &'static str = dotenv!("BACKEND_URL"); let backend_url : &'static str = dotenv!("BACKEND_URL");
@@ -432,6 +432,20 @@ pub fn DropDownUser<G: Html>(cx: Scope, value: StringProp) -> View<G> {
#[component] #[component]
async fn ListDB<G: Html>(cx: Scope<'_>) -> View<G> { async fn ListDB<G: Html>(cx: Scope<'_>) -> View<G> {
let app_state = use_context::<AppState>(cx); let app_state = use_context::<AppState>(cx);
let callback_signal = use_context::<RcSignal<bool>>(cx);
let csignal = callback_signal.clone();
//callback_signal.clone().set(false);
create_effect(cx, || {
let app_state = app_state.clone();
let cxsignal = callback_signal.clone();
if *cxsignal.get() == true {
cxsignal.set(false);
if *app_state.pagedisplay.get() < *app_state.maxpage.get()-1 {
app_state.pagedisplay.set(*app_state.pagedisplay.get()+1);
app_state.scrolling.set(true);
}
}
});
create_effect(cx, || { create_effect(cx, || {
let app_state = app_state.clone(); let app_state = app_state.clone();
@@ -440,6 +454,8 @@ async fn ListDB<G: Html>(cx: Scope<'_>) -> View<G> {
app_state.openlibrary.track(); app_state.openlibrary.track();
app_state.internalsearch.track(); app_state.internalsearch.track();
app_state.refreshing.track(); app_state.refreshing.track();
//let csignal = csignals2.clone();
//let tempb = app_state.books.get(); //let tempb = app_state.books.get();
//spawn_local( async move { info!( //spawn_local( async move { info!(
// "The state changed. Old value: {:?}", // "The state changed. Old value: {:?}",
@@ -481,6 +497,40 @@ async fn ListDB<G: Html>(cx: Scope<'_>) -> View<G> {
}); });
} }
} }
else if *app_state.scrolling.get()==true {
app_state.scrolling.set(false);
if *app_state.internalsearch.get() == false {
info!("DB triggered");
spawn_local(async move {
let res = list_books(*app_state.pagedisplay.get(), *app_state.userid.get(), "desc".to_string())
.await.unwrap();
let mut currbooks = (*app_state.clone().books.get()).clone();
currbooks.extend(res.books.iter().cloned());
app_state.books.set(
currbooks
);
app_state.maxpage.set(
res.num_pages
)
});
} else {
info!("IntSearch triggered");
spawn_local(async move {
let res = search_books(app_state.search.get().to_string(), *app_state.pagedisplay.get(), *app_state.userid.get())
.await.unwrap();
let mut currbooks = (*app_state.clone().books.get()).clone();
currbooks.extend(res.books.iter().cloned());
app_state.books.set(
currbooks
);
app_state.maxpage.set(
res.num_pages
)
});
}
}
} else { } else {
if *app_state.refreshing.get() == false { if *app_state.refreshing.get() == false {
@@ -501,6 +551,22 @@ async fn ListDB<G: Html>(cx: Scope<'_>) -> View<G> {
}); });
let callback: Closure<dyn FnMut()> = Closure::new(move || {
//let csignal = callback_signal.clone();
csignal.set(true);
info!("Got scroll event");
});
let window = web_sys::window().expect("Failed to get window");
window
.add_event_listener_with_callback_and_bool(
"scroll",
callback.as_ref().unchecked_ref(),
false, // Changing this to true does not help :/
)
.expect("Failed to set listener");
callback.forget();
let docs = create_memo(cx, || app_state.books.get().iter().cloned().collect::<Vec<_>>()); let docs = create_memo(cx, || app_state.books.get().iter().cloned().collect::<Vec<_>>());
view! {cx, view! {cx,
p { p {
@@ -1118,14 +1184,17 @@ async fn PageBar<G: Html>(cx: Scope<'_>) -> View<G> {
let input_ref = create_node_ref(cx); let input_ref = create_node_ref(cx);
let handle_add = move |_| { let handle_add = move |_| {
app_state.pagenum.set(*app_state.pagenum.get()+1); if *app_state.pagenum.get() < *app_state.maxpage.get()-1 {
app_state.refreshing.set(true); app_state.pagenum.set(*app_state.pagenum.get()+1);
app_state.pagedisplay.set(*app_state.pagenum.get()+1);
app_state.refreshing.set(true);
}
}; };
let handle_sub = move |_| { let handle_sub = move |_| {
if *app_state.pagenum.get()>1 { if *app_state.pagenum.get()>1 {
app_state.pagenum.set(*app_state.pagenum.get()-1); app_state.pagenum.set(*app_state.pagenum.get()-1);
app_state.pagedisplay.set(*app_state.pagenum.get()-1);
app_state.refreshing.set(true); app_state.refreshing.set(true);
} }
}; };
@@ -1137,6 +1206,7 @@ async fn PageBar<G: Html>(cx: Scope<'_>) -> View<G> {
let pg = currpg.get().as_ref().clone().parse::<u32>().unwrap_or(1); let pg = currpg.get().as_ref().clone().parse::<u32>().unwrap_or(1);
if pg>0 && pg<*app_state.maxpage.get() { if pg>0 && pg<*app_state.maxpage.get() {
app_state.pagenum.set(pg); app_state.pagenum.set(pg);
app_state.pagedisplay.set(pg);
app_state.refreshing.set(true); app_state.refreshing.set(true);
} else { } else {
currpg.set((*app_state.pagenum.get()).to_string()); currpg.set((*app_state.pagenum.get()).to_string());
@@ -1178,6 +1248,7 @@ async fn LoginScreenUI<G: Html>(cx: Scope<'_>) -> View<G> {
let input_refU = create_node_ref(cx); let input_refU = create_node_ref(cx);
let passval = create_signal(cx, String::new()); let passval = create_signal(cx, String::new());
let input_refP = create_node_ref(cx); let input_refP = create_node_ref(cx);
let node_ref = create_node_ref(cx);
let handle_register = move |_| { let handle_register = move |_| {
let app_state = app_state.clone(); let app_state = app_state.clone();
@@ -1198,6 +1269,8 @@ async fn LoginScreenUI<G: Html>(cx: Scope<'_>) -> View<G> {
}; };
let handle_login = move |_| { let handle_login = move |_| {
let app_state = app_state.clone();
let userstr = (*userval.get()).clone();
let user = AxumUser{ let user = AxumUser{
id: 0, id: 0,
name: (*userval.get()).clone(), name: (*userval.get()).clone(),
@@ -1207,30 +1280,59 @@ async fn LoginScreenUI<G: Html>(cx: Scope<'_>) -> View<G> {
login_user(user) login_user(user)
.await.expect("Couldn't login user"); .await.expect("Couldn't login user");
}); });
app_state.loggedin.set(true); spawn_local(async move {
app_state.useridloggedin.set( *(*app_state.userlist.get()).get(&(*userval.get()).clone()).unwrap_or(&0)); let auth = authentication_check().await.unwrap_or(false);
app_state.userid.set( *(*app_state.userlist.get()).get(&(*userval.get()).clone()).unwrap_or(&0)); app_state.loggedin.set(auth);
app_state.userscreen.set(false); if auth == true {
app_state.useridloggedin.set( *(*app_state.userlist.get()).get(&userstr).unwrap_or(&0));
app_state.userid.set( *(*app_state.userlist.get()).get(&userstr).unwrap_or(&0));
app_state.userscreen.set(false);
}
});
};
create_effect(cx, || {
if *app_state.userscreen.get() == true {
let dom_node = node_ref.try_get::<DomNode>();
if dom_node.is_some() {
dom_node.unwrap().set_attribute("popup-display","true");
}
} else {
let dom_node = node_ref.try_get::<DomNode>();
if dom_node.is_some() {
dom_node.unwrap().set_attribute("popup-display","false");
}
}
});
let handle_close = move |_| {
app_state.displaying.set(false);
let dom_node = node_ref.try_get::<DomNode>();
if dom_node.is_some() {
dom_node.unwrap().set_attribute("popup-display","false");
}
}; };
view! {cx, view! {cx,
div { div(class="modal-box", ref=node_ref){
(if *app_state.userscreen.get() == true { (if *app_state.userscreen.get() == true {
view!{cx, view!{cx,
div(class="modal-content"){
input(ref=input_refU,bind:value=userval) input(ref=input_refU,bind:value=userval)
input(ref=input_refP,bind:value=passval) input(ref=input_refP,bind:value=passval)
button(on:click=handle_login){ "LOGIN" } button(on:click=handle_login){ "LOGIN" }
button(on:click=handle_register){ "REGISTER" } button(on:click=handle_register){ "REGISTER" }
button(class="close", on:click=handle_close){ "CLOSE" }
}
} }
}else { }else {
view!{cx,""} view!{cx,""}
}) })
} }
} }
} }
@@ -1262,6 +1364,7 @@ fn App<G: Html>(cx: Scope) -> View<G> {
loggedin: create_rc_signal(bool::default()), loggedin: create_rc_signal(bool::default()),
editmode: create_rc_signal(bool::default()), editmode: create_rc_signal(bool::default()),
dropdownselect: create_rc_signal(bool::default()), dropdownselect: create_rc_signal(bool::default()),
scrolling: create_rc_signal(bool::default()),
}; };
provide_context(cx, app_state); provide_context(cx, app_state);