diff --git a/backend/api/src/lib.rs b/backend/api/src/lib.rs index 462739d..582f601 100644 --- a/backend/api/src/lib.rs +++ b/backend/api/src/lib.rs @@ -1,39 +1,41 @@ use axum::{ + extract::{Extension, Path}, http::{HeaderValue, Method, StatusCode}, response::IntoResponse, - routing::{get,post,get_service}, + routing::{get, get_service, post}, Json, Router, - extract::{Extension, Path}, }; -use clap::Parser; -use image; -use serde::{Deserialize, Serialize}; -use std::collections::HashMap; -use std::net::{IpAddr, Ipv6Addr, SocketAddr}; -use std::str::FromStr; -use std::io; -use tower::ServiceBuilder; -use tower_http::services::ServeDir; -use tower_http::cors::{Any,CorsLayer}; -use tower_http::trace::TraceLayer; -use booksman_search::BookMeili; -use booksman_search; use booksman_orm::{ sea_orm::{Database, DatabaseConnection}, - Mutation as MutationCore, Query as QueryCore -// BookAndMeta, + Mutation as MutationCore, + Query as QueryCore, // BookAndMeta, }; +use booksman_search; +use booksman_search::BookMeili; +use clap::Parser; +use image; use meilisearch_sdk::client::Client; +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; +use std::io; +use std::net::{IpAddr, Ipv6Addr, SocketAddr}; +use std::str::FromStr; +use tower::ServiceBuilder; +use tower_http::cors::{Any, CorsLayer}; +use tower_http::services::ServeDir; +use tower_http::trace::TraceLayer; //use itertools::Itertools; -use ::entity::entities::{book,book_author,book_person,book_place,book_subject,book_time,book_isbn,user}; -use std::env; -use migration::{Migrator, MigratorTrait}; -use chrono::Local; +use ::entity::entities::{ + book, book_author, book_isbn, book_person, book_place, book_subject, book_time, user, +}; use axum_login::{ axum_sessions::{async_session::MemoryStore as SessionMemoryStore, SessionLayer}, AuthLayer, RequireAuthorizationLayer, }; +use chrono::Local; +use migration::{Migrator, MigratorTrait}; use rand::Rng; +use std::env; #[derive(Deserialize, Serialize, Debug, Clone)] struct BookUI { @@ -83,7 +85,6 @@ struct Books { docs: Vec, } - #[derive(Deserialize, Serialize, Debug)] struct PaginatedBookUIList { num_pages: u32, @@ -142,7 +143,6 @@ pub struct Cover { pub medium: String, } - impl Books { fn set_all_cover_urls(&mut self) { for book in self.docs.iter_mut() { @@ -157,31 +157,38 @@ impl Books { } } } - } impl BookUI { -async fn set_descriptions(&mut self) { + async fn set_descriptions(&mut self) { + if self.open_library_key.is_some() { + if !(self.open_library_key.as_ref().unwrap().is_empty()) { + let query = format!( + "https://openlibrary.org/{}.json", + self.open_library_key.as_ref().unwrap().clone() + ); + let res = reqwest::get(query).await.expect("Unable to request"); + let resjson = res + .json::() + .await + .expect("Unable to return value"); + let description = resjson.description; - if self.open_library_key.is_some() { - if !(self.open_library_key.as_ref().unwrap().is_empty()) { - let query = format!("https://openlibrary.org/{}.json", self.open_library_key.as_ref().unwrap().clone()); - let res = reqwest::get(query).await.expect("Unable to request"); - let resjson = res.json::().await.expect("Unable to return value"); - let description = resjson.description; - - if !description.is_none() { - if let DescriptionOL::DescriptionString(desc_string) = description.clone().unwrap() { - self.description = Some(desc_string); + if !description.is_none() { + if let DescriptionOL::DescriptionString(desc_string) = + description.clone().unwrap() + { + self.description = Some(desc_string); + } + if let DescriptionOL::DescriptionValueString(desc_val) = + description.clone().unwrap() + { + self.description = Some(desc_val.value); + } + } } - if let DescriptionOL::DescriptionValueString(desc_val) = description.clone().unwrap() { - self.description = Some(desc_val.value); - } - } - } } } - } async fn handle_error(_err: io::Error) -> impl IntoResponse { @@ -209,7 +216,8 @@ struct Opt { static_dir: String, } -type AuthContext = axum_login::extractors::AuthContext; +type AuthContext = + axum_login::extractors::AuthContext; #[tokio::main] pub async fn main() { @@ -222,7 +230,6 @@ pub async fn main() { // enable console logging tracing_subscriber::fmt::init(); - dotenvy::dotenv().ok(); let images_dir = env::var("IMAGES_DIR").expect("IMAGES_DIR is not set in .env file"); let cors_url = env::var("CORS_URL").expect("CORS_URL is not set in .env file"); @@ -238,17 +245,15 @@ pub async fn main() { // Apply all pending migrations Migrator::up(&conn, None).await.unwrap(); - let session_store = SessionMemoryStore::new(); let session_layer = SessionLayer::new(session_store, &secret).with_secure(false); - let user_store = booksman_orm::AxumUserStore::new(&conn); - let auth_layer: AuthLayer = AuthLayer::new(user_store, &secret); + let auth_layer: AuthLayer = + AuthLayer::new(user_store, &secret); let meili_client = Client::new(meili_url, meili_key); - let app = Router::new() .route("/api/create_by_isbn", get(create_by_isbn)) .route("/api/create", post(create_book)) @@ -263,15 +268,21 @@ pub async fn main() { .route("/api/login", post(login_handler)) .route("/api/register", post(register_handler)) .route("/api/logout", post(logout_handler)) - .nest_service("/images", get_service(ServeDir::new(images_dir)).handle_error(handle_error)) - .nest_service("/assets", get_service(ServeDir::new(opt.static_dir)).handle_error(handle_error)) -// .merge(SpaRouter::new("/assets", opt.static_dir)) + .nest_service( + "/images", + get_service(ServeDir::new(images_dir)).handle_error(handle_error), + ) + .nest_service( + "/assets", + get_service(ServeDir::new(opt.static_dir)).handle_error(handle_error), + ) + // .merge(SpaRouter::new("/assets", opt.static_dir)) .layer(auth_layer) .layer(session_layer) .layer(ServiceBuilder::new().layer(TraceLayer::new_for_http())) - .layer(Extension(conn)) - .layer(Extension(meili_client)) - .layer( + .layer(Extension(conn)) + .layer(Extension(meili_client)) + .layer( // see https://docs.rs/tower-http/latest/tower_http/cors/index.html // for more details // @@ -280,8 +291,8 @@ pub async fn main() { // or see this issue https://github.com/tokio-rs/axum/issues/849 CorsLayer::new() .allow_methods([Method::GET, Method::POST]) - .allow_origin(cors_url.parse::().unwrap()) - .allow_headers(Any), + .allow_origin(cors_url.parse::().unwrap()) + .allow_headers(Any), ); let sock_addr = SocketAddr::from(( @@ -297,55 +308,62 @@ pub async fn main() { .expect("Unable to start server"); } - //#[axum_macros::debug_handler] - async fn register_handler(Extension(ref conn): Extension, -Json(user_sent): Json) -> impl IntoResponse { - // add to db - let user: user::Model = user::Model{ - id: user_sent.id, - user_name: Some(user_sent.clone().name), - password_hash: user_sent.clone().password_hash, - }; - let _created_user = MutationCore::create_user(conn, user).await.expect("Failed to create user"); - return "success"; - } - - -async fn list_users( +async fn register_handler( Extension(ref conn): Extension, + Json(user_sent): Json, ) -> impl IntoResponse { + // add to db + let user: user::Model = user::Model { + id: user_sent.id, + user_name: Some(user_sent.clone().name), + password_hash: user_sent.clone().password_hash, + }; + let _created_user = MutationCore::create_user(conn, user) + .await + .expect("Failed to create user"); + return "success"; +} - let usersmodels : Vec = QueryCore::list_all_users(&conn).await.unwrap_or(Vec::new()); - let mut users : Vec = Vec::new(); +async fn list_users(Extension(ref conn): Extension) -> impl IntoResponse { + let usersmodels: Vec = + QueryCore::list_all_users(&conn).await.unwrap_or(Vec::new()); + let mut users: Vec = Vec::new(); for usermodel in usersmodels.iter() { - let user = booksman_orm::AxumUser{ + let user = booksman_orm::AxumUser { id: usermodel.id, name: usermodel.user_name.clone().unwrap().clone(), - password_hash : "".to_string(), + password_hash: "".to_string(), }; users.push(user); } return Json(users); } - async fn login_handler(mut auth: AuthContext, Extension(ref conn): Extension, Json(user_sent): Json) -> impl IntoResponse { - let userdb : user::Model = QueryCore::find_userid_by_name(conn, user_sent.name.clone()).await.unwrap().unwrap(); - let userid = userdb.id; - let corrected_user = booksman_orm::AxumUser { - id: userid, - name: user_sent.name.clone(), - password_hash: user_sent.password_hash.clone() - }; - auth.login(&corrected_user).await.unwrap(); - return "success"; - } +async fn login_handler( + mut auth: AuthContext, + Extension(ref conn): Extension, + Json(user_sent): Json, +) -> impl IntoResponse { + let userdb: user::Model = QueryCore::find_userid_by_name(conn, user_sent.name.clone()) + .await + .unwrap() + .unwrap(); + let userid = userdb.id; + let corrected_user = booksman_orm::AxumUser { + id: userid, + name: user_sent.name.clone(), + password_hash: user_sent.password_hash.clone(), + }; + auth.login(&corrected_user).await.unwrap(); + return "success"; +} - // +// - async fn logout_handler(mut auth: AuthContext) { - dbg!("Logging out user: {}", &auth.current_user); - auth.logout().await; - } +async fn logout_handler(mut auth: AuthContext) { + dbg!("Logging out user: {}", &auth.current_user); + auth.logout().await; +} //https://openlibrary.org/api/books?bibkeys=ISBN:9780980200447&jscmd=data&format=json async fn authentication_check( @@ -354,7 +372,6 @@ async fn authentication_check( return Json(true); } - //https://openlibrary.org/api/books?bibkeys=ISBN:9780980200447&jscmd=data&format=json async fn create_by_isbn( Extension(ref conn): Extension, @@ -362,72 +379,147 @@ async fn create_by_isbn( Extension(user): Extension, axum::extract::Query(params): axum::extract::Query>, ) -> impl IntoResponse { - dotenvy::dotenv().ok(); let images_dir = env::var("IMAGES_DIR").expect("IMAGES_DIR is not set in .env file"); let userid = user.id; print!("Get items with query params: {:?}\n", params); let isbns = params.get("isbns").unwrap(); - let splitisbns : Vec = isbns.split(",").map(|s| format!("ISBN:{}",s.to_string())).collect(); + let splitisbns: Vec = isbns + .split(",") + .map(|s| format!("ISBN:{}", s.to_string())) + .collect(); let joinedisbns = splitisbns.join(","); - let query = format!("https://openlibrary.org/api/books?bibkeys={}&jscmd=data&format=json", joinedisbns); + let query = format!( + "https://openlibrary.org/api/books?bibkeys={}&jscmd=data&format=json", + joinedisbns + ); let res = reqwest::get(query).await.expect("Unable to request"); - let resjson: BooksManyISBN = res.json::().await.expect("Unable to return value"); + let resjson: BooksManyISBN = res + .json::() + .await + .expect("Unable to return value"); for isbnstring in splitisbns.iter() { let bookfound = resjson.book_items.get(isbnstring); if !bookfound.clone().is_none() { let mut cover_id = "".to_string(); if !bookfound.unwrap().cover.is_none() { - let coverurl = bookfound.clone().unwrap().cover.clone().unwrap().medium.clone(); - let img_bytes = reqwest::get(coverurl.clone()).await.unwrap().bytes().await.unwrap(); - let image = image::load_from_memory(&img_bytes).unwrap(); - let temp_cover = coverurl.clone(); - let img_id = temp_cover.split("/").last().unwrap(); - image.save(format!("{}/{}",images_dir,img_id)).expect("Failed to save image"); - cover_id = img_id.to_string(); - + let coverurl = bookfound + .clone() + .unwrap() + .cover + .clone() + .unwrap() + .medium + .clone(); + let img_bytes = reqwest::get(coverurl.clone()) + .await + .unwrap() + .bytes() + .await + .unwrap(); + let image = image::load_from_memory(&img_bytes).unwrap(); + let temp_cover = coverurl.clone(); + let img_id = temp_cover.split("/").last().unwrap(); + image + .save(format!("{}/{}", images_dir, img_id)) + .expect("Failed to save image"); + cover_id = img_id.to_string(); } let mut goodread_id = "".to_string(); if !bookfound.unwrap().identifiers.is_none() { - let goodread_identifier = bookfound.clone().unwrap().identifiers.clone().unwrap().goodreads; + let goodread_identifier = bookfound + .clone() + .unwrap() + .identifiers + .clone() + .unwrap() + .goodreads; if !goodread_identifier.is_none() { goodread_id = goodread_identifier.unwrap().get(0).unwrap().to_string() } } //let mut authors_name = Some(vec!["".to_string()]); //if !bookfound.unwrap().authors.is_none() { - let authors_name = Some(bookfound.clone().unwrap().authors.iter().map(|s| s.name.clone()).collect()); + let authors_name = Some( + bookfound + .clone() + .unwrap() + .authors + .iter() + .map(|s| s.name.clone()) + .collect(), + ); //} else { // authors_name = None //} - let persons : Option>; + let persons: Option>; //= Some(vec!["".to_string()]); if !bookfound.unwrap().subject_people.is_none() { - persons = Some(bookfound.clone().unwrap().subject_people.clone().unwrap().iter().map(|s| s.name.clone()).collect()); + persons = Some( + bookfound + .clone() + .unwrap() + .subject_people + .clone() + .unwrap() + .iter() + .map(|s| s.name.clone()) + .collect(), + ); } else { persons = None; } - let places : Option>; + let places: Option>; if !bookfound.unwrap().subject_places.is_none() { - places = Some(bookfound.clone().unwrap().subject_places.clone().unwrap().iter().map(|s| s.name.clone()).collect()); + places = Some( + bookfound + .clone() + .unwrap() + .subject_places + .clone() + .unwrap() + .iter() + .map(|s| s.name.clone()) + .collect(), + ); } else { places = None; } - let subjects : Option>; + let subjects: Option>; if !bookfound.unwrap().subjects.is_none() { - subjects = Some(bookfound.clone().unwrap().subjects.clone().unwrap().iter().map(|s| s.name.clone()).collect()); + subjects = Some( + bookfound + .clone() + .unwrap() + .subjects + .clone() + .unwrap() + .iter() + .map(|s| s.name.clone()) + .collect(), + ); } else { subjects = None; } - let times : Option>; + let times: Option>; if !bookfound.unwrap().subject_times.is_none() { - times = Some(bookfound.clone().unwrap().subject_times.clone().unwrap().iter().map(|s| s.name.clone()).collect()); + times = Some( + bookfound + .clone() + .unwrap() + .subject_times + .clone() + .unwrap() + .iter() + .map(|s| s.name.clone()) + .collect(), + ); } else { times = None; } - let mut doc_sent = BookUI{ + let mut doc_sent = BookUI { id: 1, open_library_key: Some(bookfound.clone().unwrap().key.clone()), title: bookfound.clone().unwrap().title.clone(), @@ -442,14 +534,14 @@ async fn create_by_isbn( rating: None, comments: Some("From openlibrary".to_string()), author_name: authors_name, - person: persons, + person: persons, place: places, subject: subjects, time: times, - isbn: Some(vec![isbnstring.split("ISBN:").last().unwrap().to_string()]) + isbn: Some(vec![isbnstring.split("ISBN:").last().unwrap().to_string()]), }; doc_sent.set_descriptions().await; - let book: book::Model = book::Model{ + let book: book::Model = book::Model { open_library_key: doc_sent.open_library_key.to_owned(), title: (doc_sent.title.to_owned()), edition_count: doc_sent.edition_count.to_owned(), @@ -470,100 +562,94 @@ async fn create_by_isbn( .expect("could not create book"); for author_name in doc_sent.author_name.as_ref().unwrap().iter() { - let record : book_author::Model = book_author::Model{ + let record: book_author::Model = book_author::Model { id: 1, book_id: (created_book.last_insert_id), author_name: author_name.to_owned(), }; MutationCore::create_book_author(conn, record) - .await - .expect("could not create book"); + .await + .expect("could not create book"); } for person in doc_sent.person.as_ref().unwrap().iter() { - let record : book_person::Model = book_person::Model{ + let record: book_person::Model = book_person::Model { id: 1, book_id: (created_book.last_insert_id), person: person.to_owned(), }; MutationCore::create_book_person(conn, record) - .await - .expect("could not create book"); - + .await + .expect("could not create book"); } for place in doc_sent.place.as_ref().unwrap().iter() { - let record : book_place::Model = book_place::Model{ + let record: book_place::Model = book_place::Model { id: 1, book_id: (created_book.last_insert_id), place: place.to_owned(), }; MutationCore::create_book_place(conn, record) - .await - .expect("could not create book"); - + .await + .expect("could not create book"); } for subject in doc_sent.subject.as_ref().unwrap().iter() { - let record : book_subject::Model = book_subject::Model{ + let record: book_subject::Model = book_subject::Model { id: 1, book_id: (created_book.last_insert_id), subject: subject.to_owned(), }; MutationCore::create_book_subject(conn, record) - .await - .expect("could not create book"); - + .await + .expect("could not create book"); } for time in doc_sent.time.as_ref().unwrap().iter() { - let record : book_time::Model = book_time::Model{ + let record: book_time::Model = book_time::Model { id: 1, book_id: (created_book.last_insert_id), time: time.to_owned(), }; MutationCore::create_book_time(conn, record) - .await - .expect("could not create book"); - + .await + .expect("could not create book"); } for isbn in doc_sent.isbn.as_ref().unwrap().iter() { - let record : book_isbn::Model = book_isbn::Model{ + let record: book_isbn::Model = book_isbn::Model { id: 1, book_id: (created_book.last_insert_id), isbn: isbn.to_owned(), }; MutationCore::create_book_isbn(conn, record) - .await - .expect("could not create book"); - + .await + .expect("could not create book"); } - let book_meili = BookMeili{ - id: doc_sent.id, - open_library_key: doc_sent.open_library_key.unwrap_or("".to_string()), - title: doc_sent.title, - edition_count: doc_sent.edition_count.unwrap_or(0), - first_publish_year: doc_sent.first_publish_year.unwrap_or(0), - median_page_count: doc_sent.median_page_count.unwrap_or(0), - goodread_id: doc_sent.goodread_id.unwrap_or("".to_string()), - description: doc_sent.description.unwrap_or("".to_string()), - cover: doc_sent.cover.unwrap_or("".to_string()), - location: doc_sent.location.unwrap_or("".to_string()), - time_added: doc_sent.time_added.unwrap_or("".to_string()), - rating: doc_sent.rating.unwrap_or(0), - comments: doc_sent.comments.unwrap_or("".to_string()), - author_name: doc_sent.author_name.unwrap_or(vec!["".to_string()]), - person: doc_sent.person.unwrap_or(vec!["".to_string()]), - place: doc_sent.place.unwrap_or(vec!["".to_string()]), - subject: doc_sent.subject.unwrap_or(vec!["".to_string()]), - time: doc_sent.time.unwrap_or(vec!["".to_string()]), - isbn: doc_sent.isbn.unwrap_or(vec!["".to_string()]), + let book_meili = BookMeili { + id: doc_sent.id, + open_library_key: doc_sent.open_library_key.unwrap_or("".to_string()), + title: doc_sent.title, + edition_count: doc_sent.edition_count.unwrap_or(0), + first_publish_year: doc_sent.first_publish_year.unwrap_or(0), + median_page_count: doc_sent.median_page_count.unwrap_or(0), + goodread_id: doc_sent.goodread_id.unwrap_or("".to_string()), + description: doc_sent.description.unwrap_or("".to_string()), + cover: doc_sent.cover.unwrap_or("".to_string()), + location: doc_sent.location.unwrap_or("".to_string()), + time_added: doc_sent.time_added.unwrap_or("".to_string()), + rating: doc_sent.rating.unwrap_or(0), + comments: doc_sent.comments.unwrap_or("".to_string()), + author_name: doc_sent.author_name.unwrap_or(vec!["".to_string()]), + person: doc_sent.person.unwrap_or(vec!["".to_string()]), + place: doc_sent.place.unwrap_or(vec!["".to_string()]), + subject: doc_sent.subject.unwrap_or(vec!["".to_string()]), + time: doc_sent.time.unwrap_or(vec!["".to_string()]), + isbn: doc_sent.isbn.unwrap_or(vec!["".to_string()]), }; booksman_search::create_or_update_book(book_meili, userid, meili_client).await; } else { - println!("ISBN Not found : {}",isbnstring); + println!("ISBN Not found : {}", isbnstring); } } return "Done"; } - async fn search_openlibrary( axum::extract::Query(params): axum::extract::Query>, ) -> impl IntoResponse { @@ -576,37 +662,35 @@ async fn search_openlibrary( resjson.set_all_cover_urls(); //resjson.set_all_descriptions().await; print!("Search token {:?}\n", search); -let mut vec = Vec::with_capacity(12); + let mut vec = Vec::with_capacity(12); for i in 0..12 as usize { let doc = resjson.docs[i].clone(); let mut goodread = "".to_string(); if doc.id_goodreads.is_some() { goodread = doc.id_goodreads.unwrap().get(0).unwrap().to_string(); } - vec.push( - BookUI{ - id: -((i+1) as i32), - open_library_key: Some(doc.key), - title: doc.title, - edition_count: doc.edition_count, - first_publish_year: doc.first_publish_year, - median_page_count: doc.number_of_pages_median, - goodread_id: Some(goodread), - description: doc.description, - cover: doc.cover_url, - location: None, - time_added: None, - rating: None, - comments: Some("From openlibrary".to_string()), - author_name: doc.author_name, - person: doc.person, - place: doc.place, - subject: doc.subject, - time: doc.time, - isbn: doc.isbn - } - ); -} + vec.push(BookUI { + id: -((i + 1) as i32), + open_library_key: Some(doc.key), + title: doc.title, + edition_count: doc.edition_count, + first_publish_year: doc.first_publish_year, + median_page_count: doc.number_of_pages_median, + goodread_id: Some(goodread), + description: doc.description, + cover: doc.cover_url, + location: None, + time_added: None, + rating: None, + comments: Some("From openlibrary".to_string()), + author_name: doc.author_name, + person: doc.person, + place: doc.place, + subject: doc.subject, + time: doc.time, + isbn: doc.isbn, + }); + } return Json(vec); } @@ -628,8 +712,6 @@ async fn list_book( Extension(ref conn): Extension, axum::extract::Query(params): axum::extract::Query>, ) -> impl IntoResponse { - - dotenvy::dotenv().ok(); let backend_url = env::var("BACKEND_URL").expect("BACKEND_URL is not set in .env file"); @@ -638,52 +720,93 @@ async fn list_book( let sort: String = params.get("sort").unwrap().to_string(); let per_page: usize = 12; - let books = QueryCore::find_books_plus_meta_in_page(conn,page,per_page,userid, sort) + let books = QueryCore::find_books_plus_meta_in_page(conn, page, per_page, userid, sort) .await .expect("could not list books"); -let mut resbooks: Vec = Vec::with_capacity(per_page); + let mut resbooks: Vec = Vec::with_capacity(per_page); - for bookandmeta in books.0.into_iter() { - let mut cover = bookandmeta.clone().book.cover; - if !cover.is_none() { - cover = Some(format!("{}/images/{}",backend_url, cover.unwrap())); - } else { - cover = Some(format!("{}/images/placeholder.jpg",backend_url)); + for bookandmeta in books.0.into_iter() { + let mut cover = bookandmeta.clone().book.cover; + if !cover.is_none() { + cover = Some(format!("{}/images/{}", backend_url, cover.unwrap())); + } else { + cover = Some(format!("{}/images/placeholder.jpg", backend_url)); + } + let bookui = BookUI { + id: bookandmeta.clone().book.id, + title: bookandmeta.clone().book.title, + open_library_key: bookandmeta.clone().book.open_library_key, + edition_count: bookandmeta.clone().book.edition_count, + first_publish_year: bookandmeta.clone().book.first_publish_year, + median_page_count: bookandmeta.clone().book.median_page_count, + goodread_id: bookandmeta.clone().book.goodread_id, + description: bookandmeta.clone().book.description, + cover: cover.clone(), + location: bookandmeta.clone().book.location, + time_added: bookandmeta.clone().book.time_added, + rating: bookandmeta.clone().book.rating, + comments: bookandmeta.clone().book.comments, + author_name: Some( + bookandmeta + .clone() + .authors + .into_iter() + .map(|u| u.author_name) + .collect(), + ), + person: Some( + bookandmeta + .clone() + .persons + .into_iter() + .map(|u| u.person) + .collect(), + ), + place: Some( + bookandmeta + .clone() + .places + .into_iter() + .map(|u| u.place) + .collect(), + ), + subject: Some( + bookandmeta + .clone() + .subjects + .into_iter() + .map(|u| u.subject) + .collect(), + ), + time: Some( + bookandmeta + .clone() + .times + .into_iter() + .map(|u| u.time) + .collect(), + ), + isbn: Some( + bookandmeta + .clone() + .isbns + .into_iter() + .map(|u| u.isbn) + .collect(), + ), + }; + resbooks.push(bookui); } - let bookui = BookUI{ - id: bookandmeta.clone().book.id, - title: bookandmeta.clone().book.title, - open_library_key: bookandmeta.clone().book.open_library_key, - edition_count: bookandmeta.clone().book.edition_count, - first_publish_year: bookandmeta.clone().book.first_publish_year, - median_page_count: bookandmeta.clone().book.median_page_count, - goodread_id: bookandmeta.clone().book.goodread_id, - description: bookandmeta.clone().book.description, - cover: cover.clone(), - location: bookandmeta.clone().book.location, - time_added: bookandmeta.clone().book.time_added, - rating: bookandmeta.clone().book.rating, - comments: bookandmeta.clone().book.comments, - author_name: Some(bookandmeta.clone().authors.into_iter().map(|u| u.author_name).collect() ), - person: Some(bookandmeta.clone().persons.into_iter().map(|u| u.person).collect()), - place: Some(bookandmeta.clone().places.into_iter().map(|u| u.place).collect()), - subject: Some(bookandmeta.clone().subjects.into_iter().map(|u| u.subject).collect()), - time: Some(bookandmeta.clone().times.into_iter().map(|u| u.time).collect()), - isbn: Some(bookandmeta.clone().isbns.into_iter().map(|u| u.isbn).collect()), + + let res = PaginatedBookUIList { + num_pages: books.1 as u32, + books: resbooks, }; - resbooks.push(bookui); - } - - let res = PaginatedBookUIList{ - num_pages: books.1 as u32, - books: resbooks - }; -return Json(res); - // "success" + return Json(res); + // "success" } - async fn list_search_book( Extension(ref meili_client): Extension, axum::extract::Query(params): axum::extract::Query>, @@ -695,53 +818,51 @@ async fn list_search_book( dotenvy::dotenv().ok(); let backend_url = env::var("BACKEND_URL").expect("BACKEND_URL is not set in .env file"); - let books = booksman_search::search_book(search, page, userid, meili_client) .await .expect("could not list books"); -let mut resbooks: Vec = Vec::with_capacity(12); + let mut resbooks: Vec = Vec::with_capacity(12); - for bookmeili in books.0.into_iter() { - let mut cover = bookmeili.clone().cover; - if cover!="".to_string() { - cover = format!("{}/images/{}",backend_url,cover); - } else { - cover = format!("{}/images/placeholder.jpg",backend_url); + for bookmeili in books.0.into_iter() { + let mut cover = bookmeili.clone().cover; + if cover != "".to_string() { + cover = format!("{}/images/{}", backend_url, cover); + } else { + cover = format!("{}/images/placeholder.jpg", backend_url); + } + let bookui = BookUI { + id: bookmeili.id, + title: bookmeili.title, + open_library_key: Some(bookmeili.open_library_key), + edition_count: Some(bookmeili.edition_count), + first_publish_year: Some(bookmeili.first_publish_year), + median_page_count: Some(bookmeili.median_page_count), + goodread_id: Some(bookmeili.goodread_id), + description: Some(bookmeili.description), + cover: Some(cover.clone()), + location: Some(bookmeili.location), + time_added: Some(bookmeili.time_added), + rating: Some(bookmeili.rating), + comments: Some(bookmeili.comments), + author_name: Some(bookmeili.author_name), + person: Some(bookmeili.person), + place: Some(bookmeili.place), + subject: Some(bookmeili.subject), + time: Some(bookmeili.time), + isbn: Some(bookmeili.isbn), + }; + resbooks.push(bookui); } - let bookui = BookUI{ - id: bookmeili.id, - title: bookmeili.title, - open_library_key: Some(bookmeili.open_library_key), - edition_count: Some(bookmeili.edition_count), - first_publish_year: Some(bookmeili.first_publish_year), - median_page_count: Some(bookmeili.median_page_count), - goodread_id: Some(bookmeili.goodread_id), - description: Some(bookmeili.description), - cover: Some(cover.clone()), - location: Some(bookmeili.location), - time_added: Some(bookmeili.time_added), - rating: Some(bookmeili.rating), - comments: Some(bookmeili.comments), - author_name: Some(bookmeili.author_name), - person: Some(bookmeili.person), - place: Some(bookmeili.place), - subject: Some(bookmeili.subject), - time: Some(bookmeili.time), - isbn: Some(bookmeili.isbn), + + let res = PaginatedBookUIList { + num_pages: (books.1 / 12 + 1) as u32, + books: resbooks, }; - resbooks.push(bookui); - } - - let res = PaginatedBookUIList{ - num_pages: (books.1/12+1) as u32, - books: resbooks - }; -return Json(res); - // "success" + return Json(res); + // "success" } - async fn create_book( Extension(ref conn): Extension, Extension(ref meili_client): Extension, @@ -765,101 +886,137 @@ async fn create_book( if !doc_sent.cover.is_none() { if !doc_sent.cover.clone().unwrap().is_empty() { - let img_bytes = reqwest::get(cover.unwrap()).await.unwrap().bytes().await.unwrap(); + let img_bytes = reqwest::get(cover.unwrap()) + .await + .unwrap() + .bytes() + .await + .unwrap(); let image = image::load_from_memory(&img_bytes).unwrap(); let temp_cover = doc_sent.cover.clone().unwrap(); - let img_id = format!("{}{}",Local::now().format("%Y-%m-%d-%H-%M-%S"),temp_cover.split("/").last().unwrap()); - image.save(format!("{}/{}",images_dir,img_id)).expect("Failed to save image"); + let img_id = format!( + "{}{}", + Local::now().format("%Y-%m-%d-%H-%M-%S"), + temp_cover.split("/").last().unwrap() + ); + image + .save(format!("{}/{}", images_dir, img_id)) + .expect("Failed to save image"); cover = Some(img_id.to_string()); - } + } } - let book: book::Model = book::Model{ - open_library_key: doc_sent.open_library_key.to_owned(), - title: (doc_sent.title.to_owned()), - edition_count: doc_sent.edition_count.to_owned(), - first_publish_year: (doc_sent.first_publish_year.to_owned()), - median_page_count: (doc_sent.median_page_count.to_owned()), - goodread_id: doc_sent.goodread_id.to_owned(), - description: doc_sent.description.to_owned(), - comments: doc_sent.comments.to_owned(), - cover: cover.to_owned(), - rating: doc_sent.rating.to_owned(), - time_added: doc_sent.time_added.to_owned(), - id: 1, - location: doc_sent.location.to_owned(), - user_id: userid, + let book: book::Model = book::Model { + open_library_key: doc_sent.open_library_key.to_owned(), + title: (doc_sent.title.to_owned()), + edition_count: doc_sent.edition_count.to_owned(), + first_publish_year: (doc_sent.first_publish_year.to_owned()), + median_page_count: (doc_sent.median_page_count.to_owned()), + goodread_id: doc_sent.goodread_id.to_owned(), + description: doc_sent.description.to_owned(), + comments: doc_sent.comments.to_owned(), + cover: cover.to_owned(), + rating: doc_sent.rating.to_owned(), + time_added: doc_sent.time_added.to_owned(), + id: 1, + location: doc_sent.location.to_owned(), + user_id: userid, }; let created_book = MutationCore::create_book(conn, book) .await .expect("could not create book"); - - for author_name in doc_sent.author_name.as_ref().unwrap_or(&vec!["".to_string()]).iter() { - let record : book_author::Model = book_author::Model{ + + for author_name in doc_sent + .author_name + .as_ref() + .unwrap_or(&vec!["".to_string()]) + .iter() + { + let record: book_author::Model = book_author::Model { id: 1, book_id: (created_book.last_insert_id), author_name: author_name.to_owned(), - }; + }; MutationCore::create_book_author(conn, record) - .await - .expect("could not create book"); + .await + .expect("could not create book"); } - for person in doc_sent.person.as_ref().unwrap_or(&vec!["".to_string()]).iter() { - let record : book_person::Model = book_person::Model{ + for person in doc_sent + .person + .as_ref() + .unwrap_or(&vec!["".to_string()]) + .iter() + { + let record: book_person::Model = book_person::Model { id: 1, book_id: (created_book.last_insert_id), person: person.to_owned(), - }; + }; MutationCore::create_book_person(conn, record) - .await - .expect("could not create book"); - + .await + .expect("could not create book"); } - for place in doc_sent.place.as_ref().unwrap_or(&vec!["".to_string()]).iter() { - let record : book_place::Model = book_place::Model{ + for place in doc_sent + .place + .as_ref() + .unwrap_or(&vec!["".to_string()]) + .iter() + { + let record: book_place::Model = book_place::Model { id: 1, book_id: (created_book.last_insert_id), place: place.to_owned(), - }; + }; MutationCore::create_book_place(conn, record) - .await - .expect("could not create book"); - + .await + .expect("could not create book"); } - for subject in doc_sent.subject.as_ref().unwrap_or(&vec!["".to_string()]).iter() { - let record : book_subject::Model = book_subject::Model{ + for subject in doc_sent + .subject + .as_ref() + .unwrap_or(&vec!["".to_string()]) + .iter() + { + let record: book_subject::Model = book_subject::Model { id: 1, book_id: (created_book.last_insert_id), subject: subject.to_owned(), - }; + }; MutationCore::create_book_subject(conn, record) - .await - .expect("could not create book"); - + .await + .expect("could not create book"); } - for time in doc_sent.time.as_ref().unwrap_or(&vec!["".to_string()]).iter() { - let record : book_time::Model = book_time::Model{ + for time in doc_sent + .time + .as_ref() + .unwrap_or(&vec!["".to_string()]) + .iter() + { + let record: book_time::Model = book_time::Model { id: 1, book_id: (created_book.last_insert_id), time: time.to_owned(), - }; + }; MutationCore::create_book_time(conn, record) - .await - .expect("could not create book"); - + .await + .expect("could not create book"); } - for isbn in doc_sent.isbn.as_ref().unwrap_or(&vec!["".to_string()]).iter() { - let record : book_isbn::Model = book_isbn::Model{ + for isbn in doc_sent + .isbn + .as_ref() + .unwrap_or(&vec!["".to_string()]) + .iter() + { + let record: book_isbn::Model = book_isbn::Model { id: 1, book_id: (created_book.last_insert_id), isbn: isbn.to_owned(), - }; + }; MutationCore::create_book_isbn(conn, record) - .await - .expect("could not create book"); - + .await + .expect("could not create book"); } - let book_meili = BookMeili{ + let book_meili = BookMeili { id: doc_sent.id, open_library_key: doc_sent.open_library_key.unwrap_or("".to_string()), title: doc_sent.title, @@ -882,151 +1039,192 @@ async fn create_book( }; booksman_search::create_or_update_book(book_meili, userid, meili_client).await; - "success" } - - async fn update_book( Extension(ref conn): Extension, Extension(ref meili_client): Extension, Extension(user): Extension, Json(doc_sent): Json, ) -> impl IntoResponse { -println!("Updating book"); + println!("Updating book"); dotenvy::dotenv().ok(); let images_dir = env::var("IMAGES_DIR").expect("IMAGES_DIR is not set in .env file"); let backend_url = env::var("BACKEND_URL").expect("BACKEND_URL is not set in .env file"); let userid = user.id.clone(); -let mut cover = doc_sent.cover.clone(); -if !doc_sent.cover.is_none() { - if !doc_sent.cover.clone().unwrap().is_empty() { - if doc_sent.cover.clone().unwrap().contains(&backend_url) { - cover = Some(doc_sent.cover.clone().unwrap().split("/").last().unwrap().to_string()); - } - else { - let img_bytes = reqwest::get(cover.unwrap()).await.unwrap().bytes().await.unwrap(); - let image = image::load_from_memory(&img_bytes).unwrap(); - let temp_cover = doc_sent.cover.clone().unwrap(); - let img_id = format!("{}{}",Local::now().format("%Y-%m-%d-%H-%M-%S"),temp_cover.split("/").last().unwrap()); - image.save(format!("{}/{}",images_dir,img_id)).expect("Failed to save image"); - cover = Some(img_id.to_string()); + let mut cover = doc_sent.cover.clone(); + if !doc_sent.cover.is_none() { + if !doc_sent.cover.clone().unwrap().is_empty() { + if doc_sent.cover.clone().unwrap().contains(&backend_url) { + cover = Some( + doc_sent + .cover + .clone() + .unwrap() + .split("/") + .last() + .unwrap() + .to_string(), + ); + } else { + let img_bytes = reqwest::get(cover.unwrap()) + .await + .unwrap() + .bytes() + .await + .unwrap(); + let image = image::load_from_memory(&img_bytes).unwrap(); + let temp_cover = doc_sent.cover.clone().unwrap(); + let img_id = format!( + "{}{}", + Local::now().format("%Y-%m-%d-%H-%M-%S"), + temp_cover.split("/").last().unwrap() + ); + image + .save(format!("{}/{}", images_dir, img_id)) + .expect("Failed to save image"); + cover = Some(img_id.to_string()); } + } } -} -let book: book::Model = book::Model{ - open_library_key: doc_sent.open_library_key.to_owned(), - title: (doc_sent.title.to_owned()), - edition_count: doc_sent.edition_count.to_owned(), - first_publish_year: (doc_sent.first_publish_year.to_owned()), - median_page_count: (doc_sent.median_page_count.to_owned()), - goodread_id: doc_sent.goodread_id.to_owned(), - description: doc_sent.description.to_owned(), - comments: doc_sent.comments.to_owned(), - cover: cover.to_owned(), - rating: doc_sent.rating.to_owned(), - time_added: doc_sent.time_added.to_owned(), - id: doc_sent.id.to_owned(), - location: doc_sent.location.to_owned(), - user_id: userid, + let book: book::Model = book::Model { + open_library_key: doc_sent.open_library_key.to_owned(), + title: (doc_sent.title.to_owned()), + edition_count: doc_sent.edition_count.to_owned(), + first_publish_year: (doc_sent.first_publish_year.to_owned()), + median_page_count: (doc_sent.median_page_count.to_owned()), + goodread_id: doc_sent.goodread_id.to_owned(), + description: doc_sent.description.to_owned(), + comments: doc_sent.comments.to_owned(), + cover: cover.to_owned(), + rating: doc_sent.rating.to_owned(), + time_added: doc_sent.time_added.to_owned(), + id: doc_sent.id.to_owned(), + location: doc_sent.location.to_owned(), + user_id: userid, }; MutationCore::update_book_by_id(conn, book.id, book) .await .expect("could not update book"); MutationCore::delete_book_author(conn, doc_sent.id) - .await - .expect("could not delete book authors while updating"); - MutationCore::delete_book_person(conn, doc_sent.id) - .await - .expect("could not delete book persons while updating"); + .await + .expect("could not delete book authors while updating"); + MutationCore::delete_book_person(conn, doc_sent.id) + .await + .expect("could not delete book persons while updating"); - MutationCore::delete_book_place(conn, doc_sent.id) - .await - .expect("could not delete book places while updating"); + MutationCore::delete_book_place(conn, doc_sent.id) + .await + .expect("could not delete book places while updating"); - MutationCore::delete_book_subject(conn, doc_sent.id) - .await - .expect("could not delete book subjects while updating"); + MutationCore::delete_book_subject(conn, doc_sent.id) + .await + .expect("could not delete book subjects while updating"); - MutationCore::delete_book_time(conn, doc_sent.id) - .await - .expect("could not delete book times while updating"); + MutationCore::delete_book_time(conn, doc_sent.id) + .await + .expect("could not delete book times while updating"); - MutationCore::delete_book_isbn(conn, doc_sent.id) - .await - .expect("could not delete book isbns while updating"); + MutationCore::delete_book_isbn(conn, doc_sent.id) + .await + .expect("could not delete book isbns while updating"); - for author_name in doc_sent.author_name.as_ref().unwrap_or(&vec!["".to_string()]).iter() { - let record : book_author::Model = book_author::Model{ + for author_name in doc_sent + .author_name + .as_ref() + .unwrap_or(&vec!["".to_string()]) + .iter() + { + let record: book_author::Model = book_author::Model { id: 1, book_id: doc_sent.id, author_name: author_name.to_owned(), }; MutationCore::create_book_author(conn, record) - .await - .expect("could not create book"); + .await + .expect("could not create book"); } - for person in doc_sent.person.as_ref().unwrap_or(&vec!["".to_string()]).iter() { - let record : book_person::Model = book_person::Model{ + for person in doc_sent + .person + .as_ref() + .unwrap_or(&vec!["".to_string()]) + .iter() + { + let record: book_person::Model = book_person::Model { id: 1, book_id: doc_sent.id, person: person.to_owned(), }; MutationCore::create_book_person(conn, record) - .await - .expect("could not create book"); - + .await + .expect("could not create book"); } - for place in doc_sent.place.as_ref().unwrap_or(&vec!["".to_string()]).iter() { - let record : book_place::Model = book_place::Model{ + for place in doc_sent + .place + .as_ref() + .unwrap_or(&vec!["".to_string()]) + .iter() + { + let record: book_place::Model = book_place::Model { id: 1, book_id: doc_sent.id, place: place.to_owned(), }; MutationCore::create_book_place(conn, record) - .await - .expect("could not create book"); - + .await + .expect("could not create book"); } - for subject in doc_sent.subject.as_ref().unwrap_or(&vec!["".to_string()]).iter() { - let record : book_subject::Model = book_subject::Model{ + for subject in doc_sent + .subject + .as_ref() + .unwrap_or(&vec!["".to_string()]) + .iter() + { + let record: book_subject::Model = book_subject::Model { id: 1, book_id: doc_sent.id, subject: subject.to_owned(), }; MutationCore::create_book_subject(conn, record) - .await - .expect("could not create book"); - + .await + .expect("could not create book"); } - for time in doc_sent.time.as_ref().unwrap_or(&vec!["".to_string()]).iter() { - let record : book_time::Model = book_time::Model{ + for time in doc_sent + .time + .as_ref() + .unwrap_or(&vec!["".to_string()]) + .iter() + { + let record: book_time::Model = book_time::Model { id: 1, book_id: doc_sent.id, time: time.to_owned(), }; MutationCore::create_book_time(conn, record) - .await - .expect("could not create book"); - + .await + .expect("could not create book"); } - for isbn in doc_sent.isbn.as_ref().unwrap_or(&vec!["".to_string()]).iter() { - let record : book_isbn::Model = book_isbn::Model{ + for isbn in doc_sent + .isbn + .as_ref() + .unwrap_or(&vec!["".to_string()]) + .iter() + { + let record: book_isbn::Model = book_isbn::Model { id: 1, book_id: doc_sent.id, isbn: isbn.to_owned(), }; MutationCore::create_book_isbn(conn, record) - .await - .expect("could not create book"); - + .await + .expect("could not create book"); } - let book_meili = BookMeili{ + let book_meili = BookMeili { id: doc_sent.id, open_library_key: doc_sent.open_library_key.unwrap_or("".to_string()), title: doc_sent.title, diff --git a/backend/entity/src/lib.rs b/backend/entity/src/lib.rs index 9b60289..0b8f0b5 100644 --- a/backend/entity/src/lib.rs +++ b/backend/entity/src/lib.rs @@ -1,3 +1 @@ pub mod entities; - - diff --git a/backend/migration/src/m20220101_000001_create_table.rs b/backend/migration/src/m20220101_000001_create_table.rs index 5037a25..2df80f5 100644 --- a/backend/migration/src/m20220101_000001_create_table.rs +++ b/backend/migration/src/m20220101_000001_create_table.rs @@ -10,7 +10,6 @@ impl MigrationTrait for Migration { // Replace the sample below with your own migration scripts //todo!(); - manager .create_table( Table::create() @@ -23,12 +22,17 @@ impl MigrationTrait for Migration { .auto_increment() .primary_key(), ) - .col(ColumnDef::new(User::UserName).string().unique_key().not_null()) + .col( + ColumnDef::new(User::UserName) + .string() + .unique_key() + .not_null(), + ) .col(ColumnDef::new(User::PasswordHash).string().not_null()) .to_owned(), ) - .await.expect("Migration failed"); - + .await + .expect("Migration failed"); manager .create_table( @@ -65,7 +69,8 @@ impl MigrationTrait for Migration { ) .to_owned(), ) - .await.expect("Migration failed"); + .await + .expect("Migration failed"); manager .create_table( @@ -91,7 +96,8 @@ impl MigrationTrait for Migration { ) .to_owned(), ) - .await.expect("Migration failed"); + .await + .expect("Migration failed"); manager .create_table( @@ -117,7 +123,8 @@ impl MigrationTrait for Migration { ) .to_owned(), ) - .await.expect("Migration failed"); + .await + .expect("Migration failed"); manager .create_table( @@ -143,7 +150,8 @@ impl MigrationTrait for Migration { ) .to_owned(), ) - .await.expect("Migration failed"); + .await + .expect("Migration failed"); manager .create_table( @@ -169,7 +177,8 @@ impl MigrationTrait for Migration { ) .to_owned(), ) - .await.expect("Migration failed"); + .await + .expect("Migration failed"); manager .create_table( @@ -195,7 +204,8 @@ impl MigrationTrait for Migration { ) .to_owned(), ) - .await.expect("Migration failed"); + .await + .expect("Migration failed"); manager .create_table( @@ -230,22 +240,28 @@ impl MigrationTrait for Migration { manager .drop_table(Table::drop().table(Book::Table).to_owned()) - .await.expect("Drop failed"); + .await + .expect("Drop failed"); manager .drop_table(Table::drop().table(BookAuthor::Table).to_owned()) - .await.expect("Drop failed"); + .await + .expect("Drop failed"); manager .drop_table(Table::drop().table(BookPerson::Table).to_owned()) - .await.expect("Drop failed"); + .await + .expect("Drop failed"); manager .drop_table(Table::drop().table(BookPlace::Table).to_owned()) - .await.expect("Drop failed"); + .await + .expect("Drop failed"); manager .drop_table(Table::drop().table(BookSubject::Table).to_owned()) - .await.expect("Drop failed"); + .await + .expect("Drop failed"); manager .drop_table(Table::drop().table(BookTime::Table).to_owned()) - .await.expect("Drop failed"); + .await + .expect("Drop failed"); manager .drop_table(Table::drop().table(BookISBN::Table).to_owned()) .await @@ -275,7 +291,7 @@ enum Book { TimeAdded, Rating, Comments, - UserId + UserId, } #[derive(Iden)] diff --git a/backend/orm/src/mutation.rs b/backend/orm/src/mutation.rs index 1abcfc0..ef38975 100644 --- a/backend/orm/src/mutation.rs +++ b/backend/orm/src/mutation.rs @@ -1,9 +1,11 @@ //use ::entity::entities::prelude::Book; //use ::entity::entities::{prelude::*, *}; -use ::entity::entities::user::Entity as User; use ::entity::entities::book::Entity as Book; +use ::entity::entities::user::Entity as User; //, book_author::Entity as Author, book_person::Entity as Person, book_place::Entity as Place, book_subject::Entity as Subject, book_time::Entity as Time, book_isbn::Entity as ISBN}; -use ::entity::entities::{book,book_author,book_person,book_place,book_subject,book_time,book_isbn,user}; +use ::entity::entities::{ + book, book_author, book_isbn, book_person, book_place, book_subject, book_time, user, +}; use sea_orm::*; //use ::entity::entities::prelude::Book; @@ -24,15 +26,15 @@ impl Mutation { pub async fn delete_user(db: &DbConn, id: i32) -> Result { let user: user::ActiveModel = User::find_by_id(id) - .one(db) - .await? - .ok_or(DbErr::Custom("Cannot find user.".to_owned())) - .map(Into::into)?; + .one(db) + .await? + .ok_or(DbErr::Custom("Cannot find user.".to_owned())) + .map(Into::into)?; user.delete(db).await } - pub async fn create_book( + pub async fn create_book( db: &DbConn, form_data: book::Model, ) -> Result, DbErr> { @@ -54,8 +56,8 @@ impl Mutation { }; Book::insert(record).exec(db).await } - - pub async fn create_book_author( + + pub async fn create_book_author( db: &DbConn, form_data: book_author::Model, ) -> Result { @@ -68,7 +70,7 @@ impl Mutation { .await } - pub async fn create_book_person( + pub async fn create_book_person( db: &DbConn, form_data: book_person::Model, ) -> Result { @@ -81,7 +83,7 @@ impl Mutation { .await } - pub async fn create_book_place( + pub async fn create_book_place( db: &DbConn, form_data: book_place::Model, ) -> Result { @@ -93,7 +95,7 @@ impl Mutation { .save(db) .await } - pub async fn create_book_subject( + pub async fn create_book_subject( db: &DbConn, form_data: book_subject::Model, ) -> Result { @@ -106,7 +108,7 @@ impl Mutation { .await } - pub async fn create_book_time( + pub async fn create_book_time( db: &DbConn, form_data: book_time::Model, ) -> Result { @@ -119,7 +121,7 @@ impl Mutation { .await } - pub async fn create_book_isbn( + pub async fn create_book_isbn( db: &DbConn, form_data: book_isbn::Model, ) -> Result { @@ -137,7 +139,6 @@ impl Mutation { id: i32, form_data: book::Model, ) -> Result { - let book: book::ActiveModel = Book::find_by_id(id) .one(db) .await? @@ -159,7 +160,9 @@ impl Mutation { rating: Set(form_data.rating.to_owned()), comments: Set(form_data.comments.to_owned()), user_id: Set(form_data.user_id.to_owned()), - }.update(db).await + } + .update(db) + .await } pub async fn delete_book(db: &DbConn, id: i32) -> Result { @@ -171,55 +174,50 @@ impl Mutation { book.delete(db).await } - pub async fn delete_book_author(db: &DbConn, id: i32) -> Result { - book_author::Entity::delete_many().filter( - Condition::any() - .add(book_author::Column::BookId.eq(id)) - ).exec(db).await + book_author::Entity::delete_many() + .filter(Condition::any().add(book_author::Column::BookId.eq(id))) + .exec(db) + .await } pub async fn delete_book_person(db: &DbConn, id: i32) -> Result { - book_person::Entity::delete_many().filter( - Condition::any() - .add(book_person::Column::BookId.eq(id)) - ).exec(db).await + book_person::Entity::delete_many() + .filter(Condition::any().add(book_person::Column::BookId.eq(id))) + .exec(db) + .await } - pub async fn delete_book_place(db: &DbConn, id: i32) -> Result { - book_place::Entity::delete_many().filter( - Condition::any() - .add(book_place::Column::BookId.eq(id)) - ).exec(db).await + book_place::Entity::delete_many() + .filter(Condition::any().add(book_place::Column::BookId.eq(id))) + .exec(db) + .await } - pub async fn delete_book_subject(db: &DbConn, id: i32) -> Result { - book_subject::Entity::delete_many().filter( - Condition::any() - .add(book_subject::Column::BookId.eq(id)) - ).exec(db).await + book_subject::Entity::delete_many() + .filter(Condition::any().add(book_subject::Column::BookId.eq(id))) + .exec(db) + .await } pub async fn delete_book_time(db: &DbConn, id: i32) -> Result { - book_time::Entity::delete_many().filter( - Condition::any() - .add(book_time::Column::BookId.eq(id)) - ).exec(db).await + book_time::Entity::delete_many() + .filter(Condition::any().add(book_time::Column::BookId.eq(id))) + .exec(db) + .await } - pub async fn delete_book_isbn(db: &DbConn, id: i32) -> Result { - book_isbn::Entity::delete_many().filter( - Condition::any() - .add(book_isbn::Column::BookId.eq(id)) - ).exec(db).await + book_isbn::Entity::delete_many() + .filter(Condition::any().add(book_isbn::Column::BookId.eq(id))) + .exec(db) + .await } - - pub async fn delete_all_books(db: &DbConn) -> Result { + pub async fn delete_all_books(db: &DbConn) -> Result { Book::delete_many().exec(db).await - } + } } diff --git a/backend/orm/src/query.rs b/backend/orm/src/query.rs index eb000b0..614a9a1 100644 --- a/backend/orm/src/query.rs +++ b/backend/orm/src/query.rs @@ -2,7 +2,9 @@ use ::entity::entities::book::Entity as Book; use ::entity::entities::user::Entity as User; //, book_author::Entity as Author, book_person::Entity as Person, book_place::Entity as Place, book_subject::Entity as Subject, book_time::Entity as Time, book_isbn::Entity as ISBN}; -use ::entity::entities::{book,book_author,book_person,book_place,book_subject,book_time,book_isbn,user}; +use ::entity::entities::{ + book, book_author, book_isbn, book_person, book_place, book_subject, book_time, user, +}; //use ::entity::entities::{prelude::*, *}; use sea_orm::*; //use sea_query::Expr; @@ -26,12 +28,16 @@ impl Query { Book::find_by_id(id).one(db).await } - - pub async fn find_userid_by_name(db: &DbConn, name: String) -> Result, DbErr> { - User::find().filter(user::Column::UserName.eq(name)).one(db).await + pub async fn find_userid_by_name( + db: &DbConn, + name: String, + ) -> Result, DbErr> { + User::find() + .filter(user::Column::UserName.eq(name)) + .one(db) + .await } - pub async fn find_user_by_id(db: &DbConn, id: i32) -> Result, DbErr> { User::find_by_id(id).one(db).await } @@ -39,13 +45,13 @@ impl Query { pub async fn list_all_users(db: &DbConn) -> Result, DbErr> { User::find().all(db).await } -/* pub async fn find_bookplusmeta_by_id(db: &DbConn, id: i32) -> Result, Vec)>, DbErr> { - let book = Book::find_by_id(id).one(db).await?.unwrap(); - let authors = book.find_related(Author).all(db).await?; - let persons = book.find_related(Person).all(db).await?; - Ok(Some((book, authors, persons))) - } - */ + /* pub async fn find_bookplusmeta_by_id(db: &DbConn, id: i32) -> Result, Vec)>, DbErr> { + let book = Book::find_by_id(id).one(db).await?.unwrap(); + let authors = book.find_related(Author).all(db).await?; + let persons = book.find_related(Person).all(db).await?; + Ok(Some((book, authors, persons))) + } + */ /// If ok, returns (post models, num pages). pub async fn find_books_in_page( @@ -62,20 +68,20 @@ impl Query { .order_by_desc(book::Column::Id) .paginate(db, posts_per_page); let num_pages = paginator.num_pages().await?; - return paginator.fetch_page(page - 1).await.map(|p| (p, num_pages)) + return paginator.fetch_page(page - 1).await.map(|p| (p, num_pages)); } else { let paginator = Book::find() .filter(book::Column::UserId.eq(userid)) .order_by_asc(book::Column::Id) .paginate(db, posts_per_page); let num_pages = paginator.num_pages().await?; - return paginator.fetch_page(page - 1).await.map(|p| (p, num_pages)) + return paginator.fetch_page(page - 1).await.map(|p| (p, num_pages)); } // Fetch paginated posts } -pub async fn find_books_plus_meta_in_page( + pub async fn find_books_plus_meta_in_page( db: &DbConn, page: usize, posts_per_page: usize, @@ -83,33 +89,43 @@ pub async fn find_books_plus_meta_in_page( sort: String, ) -> Result<(Vec, u64), DbErr> { // Setup paginator - let books = Self::find_books_in_page(db,page.try_into().unwrap(),posts_per_page.try_into().unwrap(),userid, sort).await?; + let books = Self::find_books_in_page( + db, + page.try_into().unwrap(), + posts_per_page.try_into().unwrap(), + userid, + sort, + ) + .await?; let book_ids: Vec = books.0.clone().into_iter().map(|b| b.id).collect(); println!("SIZE IS {} and {:?}", book_ids.len(), book_ids); let mut resbooks: Vec = Vec::with_capacity(book_ids.len()); for book in books.0.iter() { - let bauthors: Vec = book.find_related(book_author::Entity).all(db).await?; - let bpersons: Vec = book.find_related(book_person::Entity).all(db).await?; - let bplaces: Vec = book.find_related(book_place::Entity).all(db).await?; - let bsubjects: Vec = book.find_related(book_subject::Entity).all(db).await?; - let btimes: Vec = book.find_related(book_time::Entity).all(db).await?; - let bisbns: Vec = book.find_related(book_isbn::Entity).all(db).await?; + let bauthors: Vec = + book.find_related(book_author::Entity).all(db).await?; + let bpersons: Vec = + book.find_related(book_person::Entity).all(db).await?; + let bplaces: Vec = + book.find_related(book_place::Entity).all(db).await?; + let bsubjects: Vec = + book.find_related(book_subject::Entity).all(db).await?; + let btimes: Vec = + book.find_related(book_time::Entity).all(db).await?; + let bisbns: Vec = + book.find_related(book_isbn::Entity).all(db).await?; let bookandmeta = BookAndMetaV2 { - book: (book.clone()), - authors: bauthors, - persons: bpersons, - places: bplaces, - subjects: bsubjects, - times: btimes, - isbns: bisbns + book: (book.clone()), + authors: bauthors, + persons: bpersons, + places: bplaces, + subjects: bsubjects, + times: btimes, + isbns: bisbns, }; resbooks.push(bookandmeta); - } - Ok((resbooks,books.1)) + Ok((resbooks, books.1)) } - } - diff --git a/backend/orm/src/userstore.rs b/backend/orm/src/userstore.rs index 457c118..42e3cc4 100644 --- a/backend/orm/src/userstore.rs +++ b/backend/orm/src/userstore.rs @@ -1,9 +1,8 @@ -use sea_orm::*; +use crate::Query; use axum::async_trait; use axum_login::{secrecy::SecretVec, AuthUser, UserStore}; -use crate::Query; -use serde::{Serialize, Deserialize}; - +use sea_orm::*; +use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct AxumUser { @@ -16,7 +15,7 @@ type Result = std::result::Result; impl AuthUser for AxumUser where -Role: PartialOrd + PartialEq + Clone + Send + Sync + 'static, + Role: PartialOrd + PartialEq + Clone + Send + Sync + 'static, { fn get_id(&self) -> String { format!("{}", self.id) @@ -41,7 +40,7 @@ impl AxumUserStore { #[async_trait] impl UserStore for AxumUserStore where -Role: PartialOrd + PartialEq + Clone + Send + Sync + 'static, + Role: PartialOrd + PartialEq + Clone + Send + Sync + 'static, { type User = AxumUser; @@ -59,4 +58,3 @@ Role: PartialOrd + PartialEq + Clone + Send + Sync + 'static, } } } - diff --git a/backend/search/src/lib.rs b/backend/search/src/lib.rs index 181f312..4b70b1a 100644 --- a/backend/search/src/lib.rs +++ b/backend/search/src/lib.rs @@ -1,6 +1,6 @@ use meilisearch_sdk::client::*; use meilisearch_sdk::search::*; -use serde::{Serialize, Deserialize}; +use serde::{Deserialize, Serialize}; #[derive(Deserialize, Serialize, Debug, Clone)] pub struct BookMeili { @@ -27,33 +27,35 @@ pub struct BookMeili { pub async fn create_or_update_book(book: BookMeili, userid: i32, client: &Client) { // An index is where the documents are stored. - let books = client.index(format!("books{}",userid)); + let books = client.index(format!("books{}", userid)); // Add some movies in the index. If the index 'movies' does not exist, Meilisearch creates it when you first add the documents. - books.add_or_replace(&[ - book - ], Some("id")).await.unwrap(); + books.add_or_replace(&[book], Some("id")).await.unwrap(); } - pub async fn delete_book(bookid: i32, userid: i32, client: &Client) { // An index is where the documents are stored. - let books = client.index(format!("books{}",userid)); + let books = client.index(format!("books{}", userid)); books.delete_document(bookid).await.unwrap(); } - -pub async fn search_book(search: &str, page: usize, userid: i32, client: &Client) -> Result<(Vec, usize), meilisearch_sdk::errors::Error> { +pub async fn search_book( + search: &str, + page: usize, + userid: i32, + client: &Client, +) -> Result<(Vec, usize), meilisearch_sdk::errors::Error> { // An index is where the documents are stored. - let books = client.index(format!("books{}",userid)); - let results : SearchResults = books.search().with_query(search).with_offset((page-1)*12) - .execute::().await.unwrap(); + let books = client.index(format!("books{}", userid)); + let results: SearchResults = books + .search() + .with_query(search) + .with_offset((page - 1) * 12) + .execute::() + .await + .unwrap(); - let formatted_results : Vec = (results.hits).iter().map(|r| r.result.clone()).collect(); - //.iter()s.map(|r| r.formatted_result.unwrap()).collect(); - return Ok((formatted_results, results.estimated_total_hits)); + let formatted_results: Vec = + (results.hits).iter().map(|r| r.result.clone()).collect(); + //.iter()s.map(|r| r.formatted_result.unwrap()).collect(); + return Ok((formatted_results, results.estimated_total_hits)); } - - - - - diff --git a/backend/src/main.rs b/backend/src/main.rs index c127fe6..78ad9b2 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -1,4 +1,3 @@ fn main() { booksman_api::main(); } - diff --git a/frontend/src/main.rs b/frontend/src/main.rs index ddaa866..18be36c 100644 --- a/frontend/src/main.rs +++ b/frontend/src/main.rs @@ -8,12 +8,12 @@ use sycamore::futures::spawn_local; use sycamore::prelude::*; //use sycamore::suspense::Suspense; //use sycamore_router::Route; -use wasm_bindgen::JsCast; -use web_sys::{Event, HtmlInputElement, KeyboardEvent, EventTarget}; // 0.3.5 use dotenv_codegen::dotenv; use itertools::Itertools; use std::collections::HashMap; use wasm_bindgen::closure::Closure; +use wasm_bindgen::JsCast; +use web_sys::{Event, EventTarget, HtmlInputElement, KeyboardEvent}; // 0.3.5 //use gloo_timers::future::TimeoutFuture; //#[macro_use] //extern crate dotenv_codegen; @@ -99,28 +99,36 @@ pub struct AppState { } async fn login_user(user: AxumUser) -> Result { - let backend_url : &'static str = dotenv!("BACKEND_URL"); + let backend_url: &'static str = dotenv!("BACKEND_URL"); let url = format!("{}/api/login", backend_url); - let resp = Request::post(&url).body(serde_wasm_bindgen::to_value(&serde_json::to_string(&user).unwrap()).unwrap()).header("content-type","application/json").send().await?; + let resp = Request::post(&url) + .body(serde_wasm_bindgen::to_value(&serde_json::to_string(&user).unwrap()).unwrap()) + .header("content-type", "application/json") + .send() + .await?; Ok(resp) } async fn register_user(user: AxumUser) -> Result { - let backend_url : &'static str = dotenv!("BACKEND_URL"); + let backend_url: &'static str = dotenv!("BACKEND_URL"); let url = format!("{}/api/register", backend_url); - let resp = Request::post(&url).body(serde_wasm_bindgen::to_value(&serde_json::to_string(&user).unwrap()).unwrap()).header("content-type","application/json").send().await?; + let resp = Request::post(&url) + .body(serde_wasm_bindgen::to_value(&serde_json::to_string(&user).unwrap()).unwrap()) + .header("content-type", "application/json") + .send() + .await?; Ok(resp) } async fn logout_user() -> Result { - let backend_url : &'static str = dotenv!("BACKEND_URL"); + let backend_url: &'static str = dotenv!("BACKEND_URL"); let url = format!("{}/api/logout", backend_url); let resp = Request::post(&url).send().await?; Ok(resp) } -async fn list_users() -> Result, reqwasm::Error> { - let backend_url : &'static str = dotenv!("BACKEND_URL"); +async fn list_users() -> Result, reqwasm::Error> { + let backend_url: &'static str = dotenv!("BACKEND_URL"); let url = format!("{}/api/list_users", backend_url); let resp = Request::get(&url).send().await?; let users = resp.json::>().await?; @@ -131,9 +139,8 @@ async fn list_users() -> Result, reqwasm::Error> { Ok(res) } - async fn authentication_check() -> Result { - let backend_url : &'static str = dotenv!("BACKEND_URL"); + 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 { @@ -143,10 +150,9 @@ async fn authentication_check() -> Result { } } - async fn fetch_books(search: String) -> Result, reqwasm::Error> { //dotenvy::dotenv().ok(); - let backend_url : &'static str = dotenv!("BACKEND_URL"); + let backend_url: &'static str = dotenv!("BACKEND_URL"); //env::var("BACKEND_URL").expect("BACKEND_URL is not set in .env file"); let url = format!("{}/api/search_openlibrary?search={}", backend_url, search); let resp = Request::get(&url).send().await?; @@ -155,11 +161,18 @@ async fn fetch_books(search: String) -> Result, reqwasm::Error> { Ok(body) } -async fn search_books(search: String, page: u32, userid:i32) -> Result { - let backend_url : &'static str = dotenv!("BACKEND_URL"); +async fn search_books( + search: String, + page: u32, + userid: i32, +) -> Result { + let backend_url: &'static str = dotenv!("BACKEND_URL"); //"http://localhost:8081"; //env::var("BACKEND_URL").expect("BACKEND_URL is not set in .env file"); - let url = format!("{}/api/list_search?search={}&page={}&userid={}",backend_url, search, page, userid); + let url = format!( + "{}/api/list_search?search={}&page={}&userid={}", + backend_url, search, page, userid + ); let resp = Request::get(&url).send().await?; println!("Fetching books\n"); let body = resp.json::().await?; @@ -167,10 +180,14 @@ async fn search_books(search: String, page: u32, userid:i32) -> Result Result { - let backend_url : &'static str = dotenv!("BACKEND_URL"); + let backend_url: &'static str = dotenv!("BACKEND_URL"); //env::var("BACKEND_URL").expect("BACKEND_URL is not set in .env file"); let url = format!("{}/api/create", backend_url); - let resp = Request::post(&url).body(serde_wasm_bindgen::to_value(&serde_json::to_string(&record).unwrap()).unwrap()).header("content-type","application/json").send().await?; + let resp = Request::post(&url) + .body(serde_wasm_bindgen::to_value(&serde_json::to_string(&record).unwrap()).unwrap()) + .header("content-type", "application/json") + .send() + .await?; Ok(resp) } /* @@ -185,25 +202,36 @@ async fn add_books_isbns(isbns: String) -> Result Result { - let backend_url : &'static str = dotenv!("BACKEND_URL"); + let backend_url: &'static str = dotenv!("BACKEND_URL"); //env::var("BACKEND_URL").expect("BACKEND_URL is not set in .env file"); let url = format!("{}/api/update", backend_url); - let resp = Request::post(&url).body(serde_wasm_bindgen::to_value(&serde_json::to_string(&record).unwrap()).unwrap()).header("content-type","application/json").send().await?; + let resp = Request::post(&url) + .body(serde_wasm_bindgen::to_value(&serde_json::to_string(&record).unwrap()).unwrap()) + .header("content-type", "application/json") + .send() + .await?; Ok(resp) } async fn delete_book(id: i32) -> Result { - let backend_url : &'static str = dotenv!("BACKEND_URL"); + let backend_url: &'static str = dotenv!("BACKEND_URL"); //env::var("BACKEND_URL").expect("BACKEND_URL is not set in .env file"); let url = format!("{}/api/delete/{}", backend_url, id); let resp = Request::get(&url).send().await?; Ok(resp) } -async fn list_books(page: u32, userid: i32, sort: String) -> Result { - let backend_url : &'static str = dotenv!("BACKEND_URL"); +async fn list_books( + page: u32, + userid: i32, + sort: String, +) -> Result { + let backend_url: &'static str = dotenv!("BACKEND_URL"); //env::var("BACKEND_URL").expect("BACKEND_URL is not set in .env file"); - let url = format!("{}/api/list?page={}&userid={}&sort={}", backend_url, page, userid, sort); + let url = format!( + "{}/api/list?page={}&userid={}&sort={}", + backend_url, page, userid, sort + ); let resp = Request::get(&url).send().await?; println!("Fetching books\n"); //info!("BACKEND{}",backend_url); @@ -251,7 +279,6 @@ pub fn Header(cx: Scope) -> View { } }; - let handle_submit_seachall = |event: Event| { let event: KeyboardEvent = event.unchecked_into(); @@ -269,20 +296,17 @@ pub fn Header(cx: Scope) -> View { } }; - let click_listall = |_| { - app_state.openlibrary.set(false); - app_state.internalsearch.set(false); - app_state.refreshing.set(true); - - }; - - - let click_addbook = |_| { - app_state.adding.set(true); - app_state.updating.set(false); - app_state.addingbook.set(BookUI::default()); - }; + let click_listall = |_| { + app_state.openlibrary.set(false); + app_state.internalsearch.set(false); + app_state.refreshing.set(true); + }; + let click_addbook = |_| { + app_state.adding.set(true); + app_state.updating.set(false); + app_state.addingbook.set(BookUI::default()); + }; /*let handle_submit_addbulk = |event: Event| { let event: KeyboardEvent = event.unchecked_into(); @@ -300,174 +324,181 @@ pub fn Header(cx: Scope) -> View { } };*/ - - let click_logout = |_| { - spawn_local(async move { + let click_logout = |_| { + spawn_local(async move { logout_user().await.unwrap(); - }); - app_state.loggedin.set(false); - app_state.editmode.set(false); + }); + app_state.loggedin.set(false); + app_state.editmode.set(false); + }; -}; + let click_userscreen = |_| { + app_state.userscreen.set(true); + }; - let click_userscreen = |_| { - app_state.userscreen.set(true); - }; + let toggle_editmode = |_| { + //app_state.editmode.set(*editchecked.get()); + app_state.editmode.set(!(*app_state.editmode.get())); + app_state.userid.set(*app_state.useridloggedin.get()); + app_state + .selectedusername + .set((*app_state.loggedusername.get()).clone()); + }; - let toggle_editmode = |_| { - //app_state.editmode.set(*editchecked.get()); - app_state.editmode.set( !(*app_state.editmode.get()) ); - app_state.userid.set(*app_state.useridloggedin.get()); - app_state.selectedusername.set((*app_state.loggedusername.get()).clone()); - }; - - let dropdown_userselect = |_| { - let app_state = app_state.clone(); - spawn_local(async move { - app_state.userlist.set(list_users() - .await.expect("Couldn't list user")); - }); - app_state.dropdownselect.set(true); -}; + let dropdown_userselect = |_| { + let app_state = app_state.clone(); + spawn_local(async move { + app_state + .userlist + .set(list_users().await.expect("Couldn't list user")); + }); + app_state.dropdownselect.set(true); + }; create_effect(cx, || { // Calling checked.set will also update the `checked` property on the input element. editchecked.set(*completed.get()) }); -// let users = create_memo(cx, || app_state.userlist.get().keys().cloned().map(|x| StringProp{value: x}).collect::>()); - let users = create_memo(cx, || app_state.userlist.get().keys().cloned().collect::>()); - + // let users = create_memo(cx, || app_state.userlist.get().keys().cloned().map(|x| StringProp{value: x}).collect::>()); + let users = create_memo(cx, || { + app_state + .userlist + .get() + .keys() + .cloned() + .collect::>() + }); view! { cx, - header(class="sticky top-0 z-50 flex bg-slate-400 gap-x-4") { - div(class="w-1/10 flex mb-2"){ - (if *app_state.loggedin.get() == false { - view!{ cx, - button(on:click=click_userscreen, class="bg-gray-300 hover:bg-gray-200 text-gray-800 font-bold py-2 px-4 rounded inline-flex items-center w-full") { i(class="fa-solid fa-user") } - } - } else { - view!{cx, - div(class="flex gap-x-1"){ - button(on:click=click_logout, class="bg-gray-300 hover:bg-gray-200 text-gray-800 font-bold py-2 px-4 rounded inline-flex items-center w-1/2") { i(class="fa-solid fa-right-from-bracket") } - label(class="inline-flex relative items-center cursor-pointer w-1/2"){ - input( - class="sr-only peer", - type="checkbox", - on:input=toggle_editmode, - bind:checked=editchecked - ) - div(class="w-11 h-6 bg-gray-200 peer-focus:outline-none rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[10px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 peer-checked:bg-blue-600"){} - //p(class="ml-3 text-sm font-medium"){"EDIT"} + header(class="sticky top-0 z-50 flex bg-slate-400 gap-x-4") { + div(class="w-1/10 flex mb-2"){ + (if *app_state.loggedin.get() == false { + view!{ cx, + button(on:click=click_userscreen, class="bg-gray-300 hover:bg-gray-200 text-gray-800 font-bold py-2 px-4 rounded inline-flex items-center w-full") { i(class="fa-solid fa-user") } } - } - } - }) - } - - div(class="w-1/10 flex mb-2"){ - (if *app_state.editmode.get() == false { - view!{ cx, -// button(class="bg-gray-300 hover:bg-gray-200 text-gray-800 font-bold py-2 px-4 rounded inline-flex items-center ", on:click=dropdown_userselect) { - div(class="flex"){ - select(class="bg-gray-300 hover:bg-gray-200 text-gray-800 font-bold rounded inline-flex items-center w-max", on:click=dropdown_userselect) { - option(disabled=true, selected=true, hidden=true, value="", class="w-max"){("?")} - -/* (if *app_state.userid.get() == 0 { - - view!{ cx, ("SELECT")} - } else { - view!{cx, (*app_state.selectedusername.get())} - } - )*/ - //} - // (if *app_state.dropdownselect.get() == true { - //view!{cx, - Keyed( - iterable=users, - view=move |cx, x| view! { cx, - DropDownUser(value=x) - }, - key =|x| x.clone() ) - //} - //} else { - // view!{cx, ""} - //}) - } - } - - - } } - else { + } else { view!{cx, - div(class="bg-gray-300 text-gray-800 font-bold rounded inline-flex items-center px-2"){(format!(" Test {} ", *app_state.selectedusername.get()))} + div(class="flex gap-x-1"){ + button(on:click=click_logout, class="bg-gray-300 hover:bg-gray-200 text-gray-800 font-bold py-2 px-4 rounded inline-flex items-center w-1/2") { i(class="fa-solid fa-right-from-bracket") } + label(class="inline-flex relative items-center cursor-pointer w-1/2"){ + input( + class="sr-only peer", + type="checkbox", + on:input=toggle_editmode, + bind:checked=editchecked + ) + div(class="w-11 h-6 bg-gray-200 peer-focus:outline-none rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[10px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 peer-checked:bg-blue-600"){} + //p(class="ml-3 text-sm font-medium"){"EDIT"} + } + } } }) -} - - div(class="w-4/5 flex mb-2"){ - - - (if *app_state.editmode.get() == true { - view!{ cx, - - div(class="w-1/2 flex"){ - (if *app_state.userid.get() != 0 { - view!{ cx, - button(on:click=click_listall, class="bg-gray-300 hover:bg-gray-200 text-gray-800 font-bold py-2 px-4 rounded inline-flex items-center") { i(class="fa-solid fa-layer-group") span(class="inline-block"){"All" }} - div(class="min-w-40 inline-flex"){ - input(ref=input_ref2, - class = "inline-flex h-full m-0 p-1 w-full", - placeholder="🔍 Search", - bind:value=value2, - on:keyup=handle_submit_seachall, - )} - }} else { - view!{cx, ""} - }) - } - div(class="w-1/2 flex"){ - button(on:click=click_addbook, class="bg-gray-300 hover:bg-gray-200 text-gray-800 font-bold py-2 px-4 rounded inline-flex items-center") { i(class="fa-solid fa-circle-plus") span(class="inline-block"){"Add" }} - //button(on:click=click_addbook) { "+ Add New" } - //input(ref=input_ref3, - // class="new-todo", - // placeholder="Add bulk ISBNs", - // bind:value=value3, - // on:keyup=handle_submit_addbulk, - //) - div(class="min-w-40 inline-flex"){ - input(ref=input_ref, - class = "inline-flex h-full m-0 p-1 w-full", - placeholder="🔍 Internet", - bind:value=value, - on:keyup=handle_submit, - )} } - }} else { - view!{cx, - (if *app_state.userid.get() != 0 { - view!{ cx, - button(on:click=click_listall, class="bg-gray-300 hover:bg-gray-200 text-gray-800 font-bold py-2 px-4 rounded inline-flex items-center") { i(class="fa-solid fa-layer-group") span(class="inline-block"){"All" }} - div(class="min-w-40 inline-flex"){ - input(ref=input_ref2, - class = "inline-flex h-full m-0 p-1 w-full", - placeholder="🔍 Search", - bind:value=value2, - on:keyup=handle_submit_seachall, - )} - }} else { - view!{cx, ""} - }) - } - }) - } + div(class="w-1/10 flex mb-2"){ + (if *app_state.editmode.get() == false { + view!{ cx, + // button(class="bg-gray-300 hover:bg-gray-200 text-gray-800 font-bold py-2 px-4 rounded inline-flex items-center ", on:click=dropdown_userselect) { + div(class="flex"){ + select(class="bg-gray-300 hover:bg-gray-200 text-gray-800 font-bold rounded inline-flex items-center w-max", on:click=dropdown_userselect) { + option(disabled=true, selected=true, hidden=true, value="", class="w-max"){("?")} - div(class="grow flex mb-2 gap-x-1 ml-auto") { - PageBar{} - } - } + /* (if *app_state.userid.get() == 0 { + + view!{ cx, ("SELECT")} + } else { + view!{cx, (*app_state.selectedusername.get())} + } + )*/ + //} + // (if *app_state.dropdownselect.get() == true { + //view!{cx, + Keyed( + iterable=users, + view=move |cx, x| view! { cx, + DropDownUser(value=x) + }, + key =|x| x.clone() ) + //} + //} else { + // view!{cx, ""} + //}) + } + } + + + } } + else { + view!{cx, + div(class="bg-gray-300 text-gray-800 font-bold rounded inline-flex items-center px-2"){(format!(" Test {} ", *app_state.selectedusername.get()))} + } + }) } + + div(class="w-4/5 flex mb-2"){ + + + (if *app_state.editmode.get() == true { + view!{ cx, + + div(class="w-1/2 flex"){ + (if *app_state.userid.get() != 0 { + view!{ cx, + button(on:click=click_listall, class="bg-gray-300 hover:bg-gray-200 text-gray-800 font-bold py-2 px-4 rounded inline-flex items-center") { i(class="fa-solid fa-layer-group") span(class="inline-block"){"All" }} + div(class="min-w-40 inline-flex"){ + input(ref=input_ref2, + class = "inline-flex h-full m-0 p-1 w-full", + placeholder="🔍 Search", + bind:value=value2, + on:keyup=handle_submit_seachall, + )} + }} else { + view!{cx, ""} + }) + } + div(class="w-1/2 flex"){ + button(on:click=click_addbook, class="bg-gray-300 hover:bg-gray-200 text-gray-800 font-bold py-2 px-4 rounded inline-flex items-center") { i(class="fa-solid fa-circle-plus") span(class="inline-block"){"Add" }} + //button(on:click=click_addbook) { "+ Add New" } + //input(ref=input_ref3, + // class="new-todo", + // placeholder="Add bulk ISBNs", + // bind:value=value3, + // on:keyup=handle_submit_addbulk, + //) + div(class="min-w-40 inline-flex"){ + input(ref=input_ref, + class = "inline-flex h-full m-0 p-1 w-full", + placeholder="🔍 Internet", + bind:value=value, + on:keyup=handle_submit, + )} + } + + }} else { + view!{cx, + (if *app_state.userid.get() != 0 { + view!{ cx, + button(on:click=click_listall, class="bg-gray-300 hover:bg-gray-200 text-gray-800 font-bold py-2 px-4 rounded inline-flex items-center") { i(class="fa-solid fa-layer-group") span(class="inline-block"){"All" }} + div(class="min-w-40 inline-flex"){ + input(ref=input_ref2, + class = "inline-flex h-full m-0 p-1 w-full", + placeholder="🔍 Search", + bind:value=value2, + on:keyup=handle_submit_seachall, + )} + }} else { + view!{cx, ""} + }) + } + }) + } + + div(class="grow flex mb-2 gap-x-1 ml-auto") { + PageBar{} + } + } + } } #[component(inline_props)] @@ -477,7 +508,11 @@ pub fn DropDownUser(cx: Scope, value: StringProp) -> View { let valueclosure = value.clone(); let handle_select_user = move |_| { - app_state.userid.set( *(*app_state.userlist.get()).get(&(valueclosure.value).clone()).unwrap_or(&0)); + app_state.userid.set( + *(*app_state.userlist.get()) + .get(&(valueclosure.value).clone()) + .unwrap_or(&0), + ); app_state.selectedusername.set(valueclosure.value.clone()); app_state.dropdownselect.set(false); }; @@ -498,7 +533,6 @@ async fn ListDB(cx: Scope<'_>) -> View { //let csignal = callback_signal.clone(); //let csignal2 = callback_signal.clone(); - create_effect(cx, || { let app_state = app_state.clone(); if *app_state.userid.get() != 0 { @@ -515,12 +549,15 @@ async fn ListDB(cx: Scope<'_>) -> View { //let csignal2 = csignal2.clone(); if *app_state.scrollevent.get() == true { app_state.scrollevent.set(false); - info!("Scroll event result {}{}",*app_state.pagedisplay.get(), *app_state.maxpage.get() ); + info!( + "Scroll event result {}{}", + *app_state.pagedisplay.get(), + *app_state.maxpage.get() + ); if *app_state.pagedisplay.get() < *app_state.maxpage.get() { - app_state.pagedisplay.set(*app_state.pagedisplay.get()+1); + app_state.pagedisplay.set(*app_state.pagedisplay.get() + 1); app_state.scrolling.set(true); info!("Scroll update needed"); - } } }); @@ -549,69 +586,70 @@ async fn ListDB(cx: Scope<'_>) -> View { //TimeoutFuture::new(1000).await; //info!("Refresh triggered"); - if *app_state.internalsearch.get() == false { - info!("DB triggered"); - spawn_local(async move { + if *app_state.internalsearch.get() == false { + info!("DB triggered"); + spawn_local(async move { + let res = list_books( + *app_state.pagenum.get(), + *app_state.userid.get(), + "desc".to_string(), + ) + .await + .unwrap(); + app_state.books.set(res.books); + app_state.maxpage.set(res.num_pages) + }); + } else { + info!("IntSearch triggered"); - let res = list_books(*app_state.pagenum.get(), *app_state.userid.get(), "desc".to_string()) - .await.unwrap(); - app_state.books.set( - res.books - ); - 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.pagenum.get(), + *app_state.userid.get(), + ) + .await + .unwrap(); + app_state.books.set(res.books); + app_state.maxpage.set(res.num_pages) + }); + } + app_state.refreshing.set(false); + } else if *app_state.scrolling.get() == true { + if *app_state.internalsearch.get() == false { + info!("DB triggered2"); + spawn_local(async move { + let res = list_books( + *app_state_scr.pagedisplay.get(), + *app_state_scr.userid.get(), + "desc".to_string(), + ) + .await + .unwrap(); + let mut currbooks = (*app_state_scr.clone().books.get()).clone(); + currbooks.extend(res.books.iter().cloned()); + app_state_scr.books.set(currbooks); + app_state_scr.maxpage.set(res.num_pages) + }); + } else { + info!("IntSearch triggered2"); - spawn_local(async move { - let res = search_books(app_state.search.get().to_string(), *app_state.pagenum.get(), *app_state.userid.get()) - .await.unwrap(); - app_state.books.set( - res.books - ); - app_state.maxpage.set( - res.num_pages - ) - }); + spawn_local(async move { + let res = search_books( + app_state_scr.search.get().to_string(), + *app_state_scr.pagedisplay.get(), + *app_state_scr.userid.get(), + ) + .await + .unwrap(); + let mut currbooks = (*app_state_scr.clone().books.get()).clone(); + currbooks.extend(res.books.iter().cloned()); + app_state_scr.books.set(currbooks); + app_state_scr.maxpage.set(res.num_pages) + }); + } + app_state.scrolling.set(false); } - app_state.refreshing.set(false); - } - else if *app_state.scrolling.get()==true { - if *app_state.internalsearch.get() == false { - info!("DB triggered2"); - spawn_local(async move { - let res = list_books(*app_state_scr.pagedisplay.get(), *app_state_scr.userid.get(), "desc".to_string()) - .await.unwrap(); - let mut currbooks = (*app_state_scr.clone().books.get()).clone(); - currbooks.extend(res.books.iter().cloned()); - app_state_scr.books.set( - currbooks - ); - app_state_scr.maxpage.set( - res.num_pages - ) - }); - } else { - info!("IntSearch triggered2"); - - spawn_local(async move { - let res = search_books(app_state_scr.search.get().to_string(), *app_state_scr.pagedisplay.get(), *app_state_scr.userid.get()) - .await.unwrap(); - let mut currbooks = (*app_state_scr.clone().books.get()).clone(); - currbooks.extend(res.books.iter().cloned()); - app_state_scr.books.set( - currbooks - ); - app_state_scr.maxpage.set( - res.num_pages - ) - }); - } - app_state.scrolling.set(false); - } - } else { //info!("LibrarySearch triggered?"); if *app_state.refreshing.get() == false { @@ -619,20 +657,19 @@ async fn ListDB(cx: Scope<'_>) -> View { spawn_local(async move { if *app_state.search.get() != "" { if *app_state.openlibrary.get() == true { - app_state.books.set( - fetch_books(app_state.search.get().to_string() ) - .await - .unwrap(), - ) + app_state.books.set( + fetch_books(app_state.search.get().to_string()) + .await + .unwrap(), + ) } } }); } } info!("List Refreshing Done"); - }); - + let handle_load_more = move |_| { let app_state = app_state.clone(); app_state.scrollevent.set(true); @@ -656,7 +693,9 @@ async fn ListDB(cx: Scope<'_>) -> View { .expect("Failed to set listener"); callback.forget(); - let docs = create_memo(cx, || app_state.books.get().iter().cloned().collect::>()); + let docs = create_memo(cx, || { + app_state.books.get().iter().cloned().collect::>() + }); view! {cx, (if *app_state.openlibrary.get() == false && *app_state.editmode.get() == false { view!{ cx, @@ -710,48 +749,60 @@ pub fn BookDB(cx: Scope, bookitem: BookUIProp) -> View { let bookdisplay = bookitem.bookitem.clone(); let bookdisplay_div = bookitem.bookitem.clone(); let loctitle = bookitem.bookitem.clone().title.clone(); - let locauthors = bookitem.bookitem.clone().author_name.clone().unwrap_or(vec!["".to_string()]).join(", "); - let mut locdesc = bookitem.bookitem.clone().description.unwrap_or("".to_string()); + let locauthors = bookitem + .bookitem + .clone() + .author_name + .clone() + .unwrap_or(vec!["".to_string()]) + .join(", "); + let mut locdesc = bookitem + .bookitem + .clone() + .description + .unwrap_or("".to_string()); let locloc = bookitem.bookitem.clone().location.unwrap_or("".to_string()); if locdesc.clone().len() > 200 { - locdesc = format!("{:.200}...",locdesc.clone()) + locdesc = format!("{:.200}...", locdesc.clone()) } //let locref = create_rc_signal(false); - let coverurl = bookdisplay.clone().cover.clone().unwrap_or("None".to_string()); + let coverurl = bookdisplay + .clone() + .cover + .clone() + .unwrap_or("None".to_string()); let handle_delete = move |_| { app_state.deleteid.set(bookdelete.id); app_state.deleterequest.set(true); - }; create_effect(cx, || { let app_state = app_state.clone(); if *app_state.deleterequest.get() == true { spawn_local(async move { - let temp = delete_book(*app_state.deleteid.get()).await.unwrap(); - println!("{}",temp.status()); - app_state.refreshing.set(true); + let temp = delete_book(*app_state.deleteid.get()).await.unwrap(); + println!("{}", temp.status()); + app_state.refreshing.set(true); }); } app_state.deleterequest.set(false); - }); - let handle_update = move |_| { + let handle_update = move |_| { app_state.adding.set(false); app_state.updating.set(true); app_state.addingbook.set(bookupdate.clone()); }; - let handle_display = move |_| { + let handle_display = move |_| { app_state.displaying.set(true); app_state.updating.set(false); //info!("Setting displaying book {:?}",bookdisplay); app_state.displayingbook.set(bookdisplay.clone()); }; - let handle_display_div = move |_| { + let handle_display_div = move |_| { app_state.displaying.set(true); app_state.updating.set(false); //info!("Setting displaying book {:?}",bookdisplay); @@ -795,15 +846,29 @@ pub fn BookDB_View(cx: Scope, bookitem: BookUIProp) -> View { let bookdisplay = bookitem.bookitem.clone(); let bookdisplay_div = bookitem.bookitem.clone(); let loctitle = bookitem.bookitem.clone().title.clone(); - let locauthors = bookitem.bookitem.clone().author_name.clone().unwrap_or(vec!["".to_string()]).join(", "); - let mut locdesc = bookitem.bookitem.clone().description.unwrap_or("".to_string()); + let locauthors = bookitem + .bookitem + .clone() + .author_name + .clone() + .unwrap_or(vec!["".to_string()]) + .join(", "); + let mut locdesc = bookitem + .bookitem + .clone() + .description + .unwrap_or("".to_string()); let locloc = bookitem.bookitem.clone().location.unwrap_or("".to_string()); if locdesc.clone().len() > 200 { - locdesc = format!("{:.200}...",locdesc.clone()) + locdesc = format!("{:.200}...", locdesc.clone()) } - let coverurl = bookdisplay.clone().cover.clone().unwrap_or("None".to_string()); - let handle_display = move |_| { + let coverurl = bookdisplay + .clone() + .cover + .clone() + .unwrap_or("None".to_string()); + let handle_display = move |_| { app_state.displaying.set(true); app_state.updating.set(false); //info!("Setting displaying book {:?}",bookdisplay); @@ -862,8 +927,10 @@ async fn ListOL(cx: Scope<'_>) -> View { ); }); */ - - let docs = create_memo(cx, || app_state.books.get().iter().cloned().collect::>()); + + let docs = create_memo(cx, || { + app_state.books.get().iter().cloned().collect::>() + }); view! {cx, (if *app_state.openlibrary.get() == true { @@ -873,7 +940,7 @@ async fn ListOL(cx: Scope<'_>) -> View { iterable=docs, view=move |cx, x| view! { cx, BookOL(bookitem=x) - + }, key =|x| x.id ) } @@ -888,14 +955,20 @@ async fn ListOL(cx: Scope<'_>) -> View { #[component(inline_props)] pub fn BookOL(cx: Scope, bookitem: BookUIProp) -> View { let book = bookitem.bookitem.clone(); - let book_div=book.clone(); - let bookdisp=book.clone(); + let book_div = book.clone(); + let bookdisp = book.clone(); let loctitle = bookitem.bookitem.clone().title.clone(); - let locauthors = bookitem.bookitem.clone().author_name.clone().unwrap_or(vec!["".to_string()]).join(", "); - let backend_url : &'static str = dotenv!("BACKEND_URL"); + let locauthors = bookitem + .bookitem + .clone() + .author_name + .clone() + .unwrap_or(vec!["".to_string()]) + .join(", "); + let backend_url: &'static str = dotenv!("BACKEND_URL"); let mut coverurl = bookdisp.cover.clone().unwrap_or("NONE".to_string()); if coverurl == "NONE".to_string() { - coverurl = format!("{}/images/placeholder.jpg", backend_url ); + coverurl = format!("{}/images/placeholder.jpg", backend_url); } let app_state = use_context::(cx); @@ -903,7 +976,7 @@ pub fn BookOL(cx: Scope, bookitem: BookUIProp) -> View { app_state.adding.set(true); app_state.addingbook.set(book.clone()); }; - let handle_add_div = move |_| { + let handle_add_div = move |_| { app_state.adding.set(true); app_state.addingbook.set(book_div.clone()); }; @@ -928,108 +1001,320 @@ pub fn BookOL(cx: Scope, bookitem: BookUIProp) -> View { } } - #[component] async fn AddingUI(cx: Scope<'_>) -> View { let app_state = use_context::(cx); let node_ref = create_node_ref(cx); - -let inp_title = create_signal(cx, (*app_state.addingbook.get()).clone().title); -let inp_olkey = create_signal(cx, (*app_state.addingbook.get()).clone().open_library_key.unwrap_or("".to_string())); -let inp_editioncount = create_signal(cx, (*app_state.addingbook.get()).clone().edition_count.unwrap_or(0).to_string()); -let inp_publishyear = create_signal(cx, (*app_state.addingbook.get()).clone().first_publish_year.unwrap_or(0).to_string()); -let inp_medianpage = create_signal(cx, (*app_state.addingbook.get()).clone().median_page_count.unwrap_or(0).to_string()); -let inp_goodread = create_signal(cx, (*app_state.addingbook.get()).clone().goodread_id.unwrap_or("".to_string())); -let inp_desc = create_signal(cx, (*app_state.addingbook.get()).clone().description.unwrap_or("".to_string())); -let inp_cover = create_signal(cx, (*app_state.addingbook.get()).clone().cover.unwrap_or("".to_string())); -let inp_location = create_signal(cx, (*app_state.addingbook.get()).clone().location.unwrap_or("".to_string())); -let inp_rating = create_signal(cx, (*app_state.addingbook.get()).clone().location.unwrap_or("".to_string())); -let inp_comments = create_signal(cx, (*app_state.addingbook.get()).clone().comments.unwrap_or("".to_string())); -let inp_author = create_signal(cx, (*app_state.addingbook.get()).clone().author_name.unwrap_or(vec!["".to_string()]).join(", ")); -let inp_person = create_signal(cx, (*app_state.addingbook.get()).clone().person.unwrap_or(vec!["".to_string()]).join(", ")); -let inp_place = create_signal(cx, (*app_state.addingbook.get()).clone().place.unwrap_or(vec!["".to_string()]).join(", ")); -let inp_subject = create_signal(cx, (*app_state.addingbook.get()).clone().subject.unwrap_or(vec!["".to_string()]).join(", ")); -let inp_time = create_signal(cx, (*app_state.addingbook.get()).clone().time.unwrap_or(vec!["".to_string()]).join(", ")); -let inp_isbn = create_signal(cx, (*app_state.addingbook.get()).clone().isbn.unwrap_or(vec!["".to_string()]).join(", ")); + let inp_title = create_signal(cx, (*app_state.addingbook.get()).clone().title); + let inp_olkey = create_signal( + cx, + (*app_state.addingbook.get()) + .clone() + .open_library_key + .unwrap_or("".to_string()), + ); + let inp_editioncount = create_signal( + cx, + (*app_state.addingbook.get()) + .clone() + .edition_count + .unwrap_or(0) + .to_string(), + ); + let inp_publishyear = create_signal( + cx, + (*app_state.addingbook.get()) + .clone() + .first_publish_year + .unwrap_or(0) + .to_string(), + ); + let inp_medianpage = create_signal( + cx, + (*app_state.addingbook.get()) + .clone() + .median_page_count + .unwrap_or(0) + .to_string(), + ); + let inp_goodread = create_signal( + cx, + (*app_state.addingbook.get()) + .clone() + .goodread_id + .unwrap_or("".to_string()), + ); + let inp_desc = create_signal( + cx, + (*app_state.addingbook.get()) + .clone() + .description + .unwrap_or("".to_string()), + ); + let inp_cover = create_signal( + cx, + (*app_state.addingbook.get()) + .clone() + .cover + .unwrap_or("".to_string()), + ); + let inp_location = create_signal( + cx, + (*app_state.addingbook.get()) + .clone() + .location + .unwrap_or("".to_string()), + ); + let inp_rating = create_signal( + cx, + (*app_state.addingbook.get()) + .clone() + .location + .unwrap_or("".to_string()), + ); + let inp_comments = create_signal( + cx, + (*app_state.addingbook.get()) + .clone() + .comments + .unwrap_or("".to_string()), + ); + let inp_author = create_signal( + cx, + (*app_state.addingbook.get()) + .clone() + .author_name + .unwrap_or(vec!["".to_string()]) + .join(", "), + ); + let inp_person = create_signal( + cx, + (*app_state.addingbook.get()) + .clone() + .person + .unwrap_or(vec!["".to_string()]) + .join(", "), + ); + let inp_place = create_signal( + cx, + (*app_state.addingbook.get()) + .clone() + .place + .unwrap_or(vec!["".to_string()]) + .join(", "), + ); + let inp_subject = create_signal( + cx, + (*app_state.addingbook.get()) + .clone() + .subject + .unwrap_or(vec!["".to_string()]) + .join(", "), + ); + let inp_time = create_signal( + cx, + (*app_state.addingbook.get()) + .clone() + .time + .unwrap_or(vec!["".to_string()]) + .join(", "), + ); + let inp_isbn = create_signal( + cx, + (*app_state.addingbook.get()) + .clone() + .isbn + .unwrap_or(vec!["".to_string()]) + .join(", "), + ); create_effect(cx, || { - -// info!("{:?}",*app_state.addingbook.get()); -inp_title.set((*app_state.addingbook.get()).clone().title); -inp_olkey.set((*app_state.addingbook.get()).clone().open_library_key.unwrap_or("".to_string())); -inp_editioncount.set((*app_state.addingbook.get()).clone().edition_count.unwrap_or(0).to_string()); -inp_publishyear.set((*app_state.addingbook.get()).clone().first_publish_year.unwrap_or(0).to_string()); -inp_medianpage.set((*app_state.addingbook.get()).clone().median_page_count.unwrap_or(0).to_string()); -inp_goodread.set((*app_state.addingbook.get()).clone().goodread_id.unwrap_or("".to_string())); -inp_desc.set((*app_state.addingbook.get()).clone().description.unwrap_or("".to_string())); -inp_cover.set((*app_state.addingbook.get()).clone().cover.unwrap_or("".to_string())); -inp_location.set((*app_state.addingbook.get()).clone().location.unwrap_or("".to_string())); -inp_rating.set((*app_state.addingbook.get()).clone().location.unwrap_or("".to_string())); -inp_comments.set((*app_state.addingbook.get()).clone().comments.unwrap_or("".to_string())); -inp_author.set((*app_state.addingbook.get()).clone().author_name.unwrap_or(vec!["".to_string()]).join(", ")); - inp_person.set((*app_state.addingbook.get()).clone().person.unwrap_or(vec!["".to_string()]).join(", ")); - inp_place.set((*app_state.addingbook.get()).clone().place.unwrap_or(vec!["".to_string()]).join(", ")); - inp_subject.set((*app_state.addingbook.get()).clone().subject.unwrap_or(vec!["".to_string()]).join(", ")); - inp_time.set((*app_state.addingbook.get()).clone().time.unwrap_or(vec!["".to_string()]).join(", ")); - inp_isbn.set((*app_state.addingbook.get()).clone().isbn.unwrap_or(vec!["".to_string()]).join(", ")); -}); + // info!("{:?}",*app_state.addingbook.get()); + inp_title.set((*app_state.addingbook.get()).clone().title); + inp_olkey.set( + (*app_state.addingbook.get()) + .clone() + .open_library_key + .unwrap_or("".to_string()), + ); + inp_editioncount.set( + (*app_state.addingbook.get()) + .clone() + .edition_count + .unwrap_or(0) + .to_string(), + ); + inp_publishyear.set( + (*app_state.addingbook.get()) + .clone() + .first_publish_year + .unwrap_or(0) + .to_string(), + ); + inp_medianpage.set( + (*app_state.addingbook.get()) + .clone() + .median_page_count + .unwrap_or(0) + .to_string(), + ); + inp_goodread.set( + (*app_state.addingbook.get()) + .clone() + .goodread_id + .unwrap_or("".to_string()), + ); + inp_desc.set( + (*app_state.addingbook.get()) + .clone() + .description + .unwrap_or("".to_string()), + ); + inp_cover.set( + (*app_state.addingbook.get()) + .clone() + .cover + .unwrap_or("".to_string()), + ); + inp_location.set( + (*app_state.addingbook.get()) + .clone() + .location + .unwrap_or("".to_string()), + ); + inp_rating.set( + (*app_state.addingbook.get()) + .clone() + .location + .unwrap_or("".to_string()), + ); + inp_comments.set( + (*app_state.addingbook.get()) + .clone() + .comments + .unwrap_or("".to_string()), + ); + inp_author.set( + (*app_state.addingbook.get()) + .clone() + .author_name + .unwrap_or(vec!["".to_string()]) + .join(", "), + ); + inp_person.set( + (*app_state.addingbook.get()) + .clone() + .person + .unwrap_or(vec!["".to_string()]) + .join(", "), + ); + inp_place.set( + (*app_state.addingbook.get()) + .clone() + .place + .unwrap_or(vec!["".to_string()]) + .join(", "), + ); + inp_subject.set( + (*app_state.addingbook.get()) + .clone() + .subject + .unwrap_or(vec!["".to_string()]) + .join(", "), + ); + inp_time.set( + (*app_state.addingbook.get()) + .clone() + .time + .unwrap_or(vec!["".to_string()]) + .join(", "), + ); + inp_isbn.set( + (*app_state.addingbook.get()) + .clone() + .isbn + .unwrap_or(vec!["".to_string()]) + .join(", "), + ); + }); - let handle_cancel = |_| { + let handle_cancel = |_| { app_state.updating.set(false); app_state.adding.set(false); let dom_node = node_ref.try_get::(); if dom_node.is_some() { - dom_node.unwrap().set_attribute("popup-display","false"); + dom_node.unwrap().set_attribute("popup-display", "false"); } + }; - }; - - let handle_add = |_| { -info!("Adding book"); - let authors: Vec = (*inp_author.get()).clone().split(",").map(str::to_string).collect::>(); - let persons: Vec = (*inp_person.get()).clone().split(",").map(str::to_string).collect::>(); - let places: Vec = (*inp_place.get()).clone().split(",").map(|x| x.to_string()).collect::>(); - let subjects: Vec = (*inp_subject.get()).clone().split(",").map(|x| x.to_string()).collect::>(); - let times: Vec = (*inp_time.get()).clone().split(",").map(|x| x.to_string()).collect::>(); - let isbns: Vec = (*inp_isbn.get()).clone().split(",").map(|x| x.to_string()).collect::>(); - let record : BookUI = BookUI{ - id: app_state.addingbook.get().id.clone(), - title: (*inp_title.get()).clone(), - open_library_key: Some((*inp_olkey.get()).clone()), - edition_count: Some(inp_editioncount.get().parse::().unwrap_or(0)), - first_publish_year: Some(inp_publishyear.get().parse::().unwrap_or(0)), - median_page_count: Some(inp_medianpage.get().parse::().unwrap_or(0)), - goodread_id: Some((*inp_goodread.get()).clone()), - description: Some((*inp_desc.get()).clone()), - cover: Some((*inp_cover.get()).clone()), - location: Some((*inp_location.get()).clone()), - time_added: Some("NA".to_string()), - rating: Some(inp_rating.get().parse::().unwrap_or(0)), - comments: Some((*inp_comments.get()).clone()), - author_name: Some(authors), - person: Some(persons), - place: Some(places), - subject: Some(subjects), - time: Some(times), - isbn: Some(isbns), - }; + let handle_add = |_| { + info!("Adding book"); + let authors: Vec = (*inp_author.get()) + .clone() + .split(",") + .map(str::to_string) + .collect::>(); + let persons: Vec = (*inp_person.get()) + .clone() + .split(",") + .map(str::to_string) + .collect::>(); + let places: Vec = (*inp_place.get()) + .clone() + .split(",") + .map(|x| x.to_string()) + .collect::>(); + let subjects: Vec = (*inp_subject.get()) + .clone() + .split(",") + .map(|x| x.to_string()) + .collect::>(); + let times: Vec = (*inp_time.get()) + .clone() + .split(",") + .map(|x| x.to_string()) + .collect::>(); + let isbns: Vec = (*inp_isbn.get()) + .clone() + .split(",") + .map(|x| x.to_string()) + .collect::>(); + let record: BookUI = BookUI { + id: app_state.addingbook.get().id.clone(), + title: (*inp_title.get()).clone(), + open_library_key: Some((*inp_olkey.get()).clone()), + edition_count: Some(inp_editioncount.get().parse::().unwrap_or(0)), + first_publish_year: Some(inp_publishyear.get().parse::().unwrap_or(0)), + median_page_count: Some(inp_medianpage.get().parse::().unwrap_or(0)), + goodread_id: Some((*inp_goodread.get()).clone()), + description: Some((*inp_desc.get()).clone()), + cover: Some((*inp_cover.get()).clone()), + location: Some((*inp_location.get()).clone()), + time_added: Some("NA".to_string()), + rating: Some(inp_rating.get().parse::().unwrap_or(0)), + comments: Some((*inp_comments.get()).clone()), + author_name: Some(authors), + person: Some(persons), + place: Some(places), + subject: Some(subjects), + time: Some(times), + isbn: Some(isbns), + }; app_state.apibook.set(record); app_state.addingbook.set(BookUI::default()); - if *app_state.updating.get()==true { + if *app_state.updating.get() == true { app_state.updatingrequest.set(true); } - if *app_state.adding.get()==true { + if *app_state.adding.get() == true { app_state.addingrequest.set(true); } app_state.updating.set(false); app_state.adding.set(false); //app_state.books.set(vec![BookUI::default()]); - - }; create_effect(cx, || { @@ -1039,222 +1324,30 @@ info!("Adding book"); spawn_local(async move { info!("Adding effect startedDone"); - if *app_state.addingrequest.get() == true { - let temp = add_book(record).await.unwrap(); - info!("Adding Done{}",temp.status()); - app_state.refreshing.set(true); - app_state.addingrequest.set(false); - } else if *app_state.updatingrequest.get() == true { - let temp = update_book(record).await.unwrap(); - info!("Updating Done{}",temp.status()); - app_state.refreshing.set(true); - app_state.updatingrequest.set(false); - } + if *app_state.addingrequest.get() == true { + let temp = add_book(record).await.unwrap(); + info!("Adding Done{}", temp.status()); + app_state.refreshing.set(true); + app_state.addingrequest.set(false); + } else if *app_state.updatingrequest.get() == true { + let temp = update_book(record).await.unwrap(); + info!("Updating Done{}", temp.status()); + app_state.refreshing.set(true); + app_state.updatingrequest.set(false); + } }); - }); - - create_effect(cx, || { - if *app_state.updating.get() == true || *app_state.adding.get() == true { - - let dom_node = node_ref.try_get::(); - if dom_node.is_some() { - dom_node.unwrap().set_attribute("popup-display","true"); - } - } else { - let dom_node = node_ref.try_get::(); - if dom_node.is_some() { - dom_node.unwrap().set_attribute("popup-display","false"); - } - } }); - let handle_click_close = |event: Event| { - let target: EventTarget = event.target().unwrap(); - let element: web_sys::Element = target.unchecked_into(); - if element.has_attribute("closable") - { - app_state.displaying.set(false); - - let dom_node = node_ref.try_get::(); - if dom_node.is_some() { - dom_node.unwrap().set_attribute("popup-display","false"); - } - } - }; - - view! {cx, - div(class="modal-box",ref=node_ref, on:click=handle_click_close, closable="true"){ - -(if *app_state.adding.get() == true || *app_state.updating.get() == true { - view!{ cx, - div(class="modal-content"){ - div(class="input-buttons flex gap-x-3"){ - button( class="bg-gray-300 hover:bg-gray-400 text-gray-800 font-bold py-2 px-4 rounded inline-flex items-center", on:click=handle_add){ "Add/Update" } - button( class="bg-gray-300 hover:bg-gray-400 text-gray-800 font-bold py-2 px-4 rounded inline-flex items-center", on:click=handle_cancel){ "Cancel" } - } - p { - div(class="flex flex-wrap w-full"){ - - div(class="grid grid-cols-1 md:grid-cols-3 lg:grid=cols-4 gap-x-4"){ - - div(class="input-field grid grid-row-2"){ - label{"Title"} - textarea(bind:value=inp_title, placeholder="Title" ) - } - div(class="input-field grid grid-row-2"){ - label{"OpenLib Key"} - textarea(bind:value=inp_olkey, placeholder="OpenLibrary Key" ) - } - div(class="input-field grid grid-row-2"){ - label{"Editions"} - textarea(bind:value=inp_editioncount, placeholder="Number of editions" ) - } - div(class="input-field grid grid-row-2"){ - label{"Publish year"} - textarea(bind:value=inp_publishyear, placeholder="First publish year" ) - } - div(class="input-field grid grid-row-2"){ - label{"Pages"} - textarea(bind:value=inp_medianpage, placeholder="Page count" ) - } - div(class="input-field grid grid-row-2"){ - label{"GoodreadID"} - textarea(bind:value=inp_goodread, placeholder="GoodRead ID" ) - } - div(class="input-field grid grid-row-2"){ - label{"Description"} - textarea(bind:value=inp_desc, placeholder="Description" ) - } - div(class="input-field grid grid-row-2"){ - label{"Cover"} - textarea(bind:value=inp_cover, placeholder="Cover URL" ) - } - div(class="input-field grid grid-row-2"){ - label{"Location"} - textarea(bind:value=inp_location, placeholder="Location" ) - } - div(class="input-field grid grid-row-2"){ - label{"Rating"} - textarea(bind:value=inp_rating, placeholder="Rating (/10)" ) - } - div(class="input-field grid grid-row-2"){ - label{"Comments"} - textarea(bind:value=inp_comments, placeholder="Comments" ) - } - div(class="input-field grid grid-row-2"){ - label{"Authors"} - textarea(bind:value=inp_author, placeholder="Authors") - } - div(class="input-field grid grid-row-2"){ - label{"Persons"} - textarea(bind:value=inp_person, placeholder="Persons" ) - } - div(class="input-field grid grid-row-2"){ - label{"Places"} - textarea(bind:value=inp_place, placeholder="Places" ) - } - div(class="input-field grid grid-row-2"){ - label{"Subjects"} - textarea(bind:value=inp_subject, placeholder="Subjects" ) - } - div(class="input-field grid grid-row-2"){ - label{"Times"} - textarea(bind:value=inp_time, placeholder="Times" ) - } - div(class="input-field grid grid-row-2"){ - label{"ISBNs"} - textarea(bind:value=inp_isbn, placeholder="ISBNs" ) - } - } - } - - } - } - - } - } - else { - view!{cx,""} - }) - } - - } - -} - - -#[component] -async fn SelectedUI(cx: Scope<'_>) -> View { - let app_state = use_context::(cx); - let displaybook = create_memo(cx, || app_state.displayingbook.get()); - - let coverurl = create_memo(cx, || app_state.displayingbook.get().clone().cover.clone().unwrap_or("NONE".to_string()).to_string().clone()); - let node_ref = create_node_ref(cx); - - let dtitle = create_memo(cx, || app_state.displayingbook.get().title.clone()); - let dollink = create_memo(cx, || { - let olkey = app_state.displayingbook.get().open_library_key.clone().unwrap_or("".to_string()); - format!("https://openlibrary.org{}",olkey) - } - ); - let deditions = create_memo(cx, || app_state.displayingbook.get().edition_count.unwrap_or(0) ); - let dpubyr = create_memo(cx, || app_state.displayingbook.get().first_publish_year.unwrap_or(0) ); - let dpages = create_memo(cx, || app_state.displayingbook.get().median_page_count.unwrap_or(0) ); - let dgoodread = create_memo(cx, || { - let goodreadid = app_state.displayingbook.get().goodread_id.clone().unwrap_or("".to_string()); - format!("https://goodreads.com/en/book/show/{}",goodreadid) - } - ); - let ddesc = create_memo(cx, || app_state.displayingbook.get().description.clone().unwrap_or("".to_string()) ); - let dlocation = create_memo(cx, || app_state.displayingbook.get().location.clone().unwrap_or("".to_string()) ); - let dcomments = create_memo(cx, || app_state.displayingbook.get().comments.clone().unwrap_or("".to_string()) ); - let dtags = create_memo(cx, || { - let persons = app_state.displayingbook.get().person.clone().unwrap_or(vec!["".to_string()]).iter().filter(|word| !word.is_empty()).map(|s| format!("#{}",s.clone())).collect::>().join(", "); - let places = app_state.displayingbook.get().place.clone().unwrap_or(vec!["".to_string()]).iter().filter(|word| !word.is_empty()).map(|s| format!("#{}",s.clone())).collect::>().join(", "); - let subjects = app_state.displayingbook.get().subject.clone().unwrap_or(vec!["".to_string()]).iter().filter(|word| !word.is_empty()).map(|s| format!("#{}",s.clone())).collect::>().join(", "); - let times = app_state.displayingbook.get().time.clone().unwrap_or(vec!["".to_string()]).iter().filter(|word| !word.is_empty()).map(|s| format!("#{}",s.clone())).collect::>().join(", "); - let alltags = vec![persons,places,subjects,times].iter().filter(|word| !word.is_empty()).join(", "); - format!("{}",alltags) - } - ); - let disbn = create_memo(cx, || { - app_state.displayingbook.get().isbn.clone().unwrap_or(vec!["".to_string()])[0].clone() - }); - let dauthors = create_memo(cx, || { - app_state.displayingbook.get().author_name.clone().unwrap_or(vec!["".to_string()]).join(", ") - }); - - let handle_close = move |_| { - app_state.displaying.set(false); - - let dom_node = node_ref.try_get::(); - if dom_node.is_some() { - dom_node.unwrap().set_attribute("popup-display","false"); - } - }; - - let handle_edit = move |_| { - app_state.displaying.set(false); - let dom_node = node_ref.try_get::(); - if dom_node.is_some() { - dom_node.unwrap().set_attribute("popup-display","false"); - } - - app_state.addingbook.set((*(*displaybook.get())).clone()); - app_state.updating.set(true); - }; - - create_effect(cx, || { - if *app_state.displaying.get() == true { + if *app_state.updating.get() == true || *app_state.adding.get() == true { let dom_node = node_ref.try_get::(); if dom_node.is_some() { - dom_node.unwrap().set_attribute("popup-display","true"); + dom_node.unwrap().set_attribute("popup-display", "true"); } } else { let dom_node = node_ref.try_get::(); if dom_node.is_some() { - dom_node.unwrap().set_attribute("popup-display","false"); + dom_node.unwrap().set_attribute("popup-display", "false"); } } }); @@ -1262,13 +1355,306 @@ async fn SelectedUI(cx: Scope<'_>) -> View { let handle_click_close = |event: Event| { let target: EventTarget = event.target().unwrap(); let element: web_sys::Element = target.unchecked_into(); - if element.has_attribute("closable") - { + if element.has_attribute("closable") { app_state.displaying.set(false); let dom_node = node_ref.try_get::(); if dom_node.is_some() { - dom_node.unwrap().set_attribute("popup-display","false"); + dom_node.unwrap().set_attribute("popup-display", "false"); + } + } + }; + + view! {cx, + div(class="modal-box",ref=node_ref, on:click=handle_click_close, closable="true"){ + + (if *app_state.adding.get() == true || *app_state.updating.get() == true { + view!{ cx, + div(class="modal-content"){ + div(class="input-buttons flex gap-x-3"){ + button( class="bg-gray-300 hover:bg-gray-400 text-gray-800 font-bold py-2 px-4 rounded inline-flex items-center", on:click=handle_add){ "Add/Update" } + button( class="bg-gray-300 hover:bg-gray-400 text-gray-800 font-bold py-2 px-4 rounded inline-flex items-center", on:click=handle_cancel){ "Cancel" } + } + p { + div(class="flex flex-wrap w-full"){ + + div(class="grid grid-cols-1 md:grid-cols-3 lg:grid=cols-4 gap-x-4"){ + + div(class="input-field grid grid-row-2"){ + label{"Title"} + textarea(bind:value=inp_title, placeholder="Title" ) + } + div(class="input-field grid grid-row-2"){ + label{"OpenLib Key"} + textarea(bind:value=inp_olkey, placeholder="OpenLibrary Key" ) + } + div(class="input-field grid grid-row-2"){ + label{"Editions"} + textarea(bind:value=inp_editioncount, placeholder="Number of editions" ) + } + div(class="input-field grid grid-row-2"){ + label{"Publish year"} + textarea(bind:value=inp_publishyear, placeholder="First publish year" ) + } + div(class="input-field grid grid-row-2"){ + label{"Pages"} + textarea(bind:value=inp_medianpage, placeholder="Page count" ) + } + div(class="input-field grid grid-row-2"){ + label{"GoodreadID"} + textarea(bind:value=inp_goodread, placeholder="GoodRead ID" ) + } + div(class="input-field grid grid-row-2"){ + label{"Description"} + textarea(bind:value=inp_desc, placeholder="Description" ) + } + div(class="input-field grid grid-row-2"){ + label{"Cover"} + textarea(bind:value=inp_cover, placeholder="Cover URL" ) + } + div(class="input-field grid grid-row-2"){ + label{"Location"} + textarea(bind:value=inp_location, placeholder="Location" ) + } + div(class="input-field grid grid-row-2"){ + label{"Rating"} + textarea(bind:value=inp_rating, placeholder="Rating (/10)" ) + } + div(class="input-field grid grid-row-2"){ + label{"Comments"} + textarea(bind:value=inp_comments, placeholder="Comments" ) + } + div(class="input-field grid grid-row-2"){ + label{"Authors"} + textarea(bind:value=inp_author, placeholder="Authors") + } + div(class="input-field grid grid-row-2"){ + label{"Persons"} + textarea(bind:value=inp_person, placeholder="Persons" ) + } + div(class="input-field grid grid-row-2"){ + label{"Places"} + textarea(bind:value=inp_place, placeholder="Places" ) + } + div(class="input-field grid grid-row-2"){ + label{"Subjects"} + textarea(bind:value=inp_subject, placeholder="Subjects" ) + } + div(class="input-field grid grid-row-2"){ + label{"Times"} + textarea(bind:value=inp_time, placeholder="Times" ) + } + div(class="input-field grid grid-row-2"){ + label{"ISBNs"} + textarea(bind:value=inp_isbn, placeholder="ISBNs" ) + } + } + } + + } + } + + } + } + else { + view!{cx,""} + }) + } + + } +} + +#[component] +async fn SelectedUI(cx: Scope<'_>) -> View { + let app_state = use_context::(cx); + let displaybook = create_memo(cx, || app_state.displayingbook.get()); + + let coverurl = create_memo(cx, || { + app_state + .displayingbook + .get() + .clone() + .cover + .clone() + .unwrap_or("NONE".to_string()) + .to_string() + .clone() + }); + let node_ref = create_node_ref(cx); + + let dtitle = create_memo(cx, || app_state.displayingbook.get().title.clone()); + let dollink = create_memo(cx, || { + let olkey = app_state + .displayingbook + .get() + .open_library_key + .clone() + .unwrap_or("".to_string()); + format!("https://openlibrary.org{}", olkey) + }); + let deditions = create_memo(cx, || { + app_state.displayingbook.get().edition_count.unwrap_or(0) + }); + let dpubyr = create_memo(cx, || { + app_state + .displayingbook + .get() + .first_publish_year + .unwrap_or(0) + }); + let dpages = create_memo(cx, || { + app_state + .displayingbook + .get() + .median_page_count + .unwrap_or(0) + }); + let dgoodread = create_memo(cx, || { + let goodreadid = app_state + .displayingbook + .get() + .goodread_id + .clone() + .unwrap_or("".to_string()); + format!("https://goodreads.com/en/book/show/{}", goodreadid) + }); + let ddesc = create_memo(cx, || { + app_state + .displayingbook + .get() + .description + .clone() + .unwrap_or("".to_string()) + }); + let dlocation = create_memo(cx, || { + app_state + .displayingbook + .get() + .location + .clone() + .unwrap_or("".to_string()) + }); + let dcomments = create_memo(cx, || { + app_state + .displayingbook + .get() + .comments + .clone() + .unwrap_or("".to_string()) + }); + let dtags = create_memo(cx, || { + let persons = app_state + .displayingbook + .get() + .person + .clone() + .unwrap_or(vec!["".to_string()]) + .iter() + .filter(|word| !word.is_empty()) + .map(|s| format!("#{}", s.clone())) + .collect::>() + .join(", "); + let places = app_state + .displayingbook + .get() + .place + .clone() + .unwrap_or(vec!["".to_string()]) + .iter() + .filter(|word| !word.is_empty()) + .map(|s| format!("#{}", s.clone())) + .collect::>() + .join(", "); + let subjects = app_state + .displayingbook + .get() + .subject + .clone() + .unwrap_or(vec!["".to_string()]) + .iter() + .filter(|word| !word.is_empty()) + .map(|s| format!("#{}", s.clone())) + .collect::>() + .join(", "); + let times = app_state + .displayingbook + .get() + .time + .clone() + .unwrap_or(vec!["".to_string()]) + .iter() + .filter(|word| !word.is_empty()) + .map(|s| format!("#{}", s.clone())) + .collect::>() + .join(", "); + let alltags = vec![persons, places, subjects, times] + .iter() + .filter(|word| !word.is_empty()) + .join(", "); + format!("{}", alltags) + }); + let disbn = create_memo(cx, || { + app_state + .displayingbook + .get() + .isbn + .clone() + .unwrap_or(vec!["".to_string()])[0] + .clone() + }); + let dauthors = create_memo(cx, || { + app_state + .displayingbook + .get() + .author_name + .clone() + .unwrap_or(vec!["".to_string()]) + .join(", ") + }); + + let handle_close = move |_| { + app_state.displaying.set(false); + + let dom_node = node_ref.try_get::(); + if dom_node.is_some() { + dom_node.unwrap().set_attribute("popup-display", "false"); + } + }; + + let handle_edit = move |_| { + app_state.displaying.set(false); + let dom_node = node_ref.try_get::(); + if dom_node.is_some() { + dom_node.unwrap().set_attribute("popup-display", "false"); + } + + app_state.addingbook.set((*(*displaybook.get())).clone()); + app_state.updating.set(true); + }; + + create_effect(cx, || { + if *app_state.displaying.get() == true { + let dom_node = node_ref.try_get::(); + if dom_node.is_some() { + dom_node.unwrap().set_attribute("popup-display", "true"); + } + } else { + let dom_node = node_ref.try_get::(); + if dom_node.is_some() { + dom_node.unwrap().set_attribute("popup-display", "false"); + } + } + }); + + let handle_click_close = |event: Event| { + let target: EventTarget = event.target().unwrap(); + let element: web_sys::Element = target.unchecked_into(); + if element.has_attribute("closable") { + app_state.displaying.set(false); + + let dom_node = node_ref.try_get::(); + if dom_node.is_some() { + dom_node.unwrap().set_attribute("popup-display", "false"); } } }; @@ -1361,10 +1747,8 @@ async fn SelectedUI(cx: Scope<'_>) -> View { }) } } - } - #[component] async fn PageBar(cx: Scope<'_>) -> View { let app_state = use_context::(cx); @@ -1373,17 +1757,17 @@ async fn PageBar(cx: Scope<'_>) -> View { let handle_add = move |_| { if *app_state.pagenum.get() < *app_state.maxpage.get() { - app_state.pagenum.set(*app_state.pagenum.get()+1); - app_state.pagedisplay.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); currpg.set((*app_state.pagenum.get()).to_string()); } }; let handle_sub = move |_| { - if *app_state.pagenum.get()>1 { - app_state.pagenum.set(*app_state.pagenum.get()-1); - app_state.pagedisplay.set(*app_state.pagenum.get()-1); + if *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); currpg.set((*app_state.pagenum.get()).to_string()); } @@ -1394,14 +1778,13 @@ async fn PageBar(cx: Scope<'_>) -> View { if event.key() == "Enter" { let pg = currpg.get().as_ref().clone().parse::().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.pagedisplay.set(pg); app_state.refreshing.set(true); } else { currpg.set((*app_state.pagenum.get()).to_string()); } - } }; view! {cx, @@ -1435,7 +1818,6 @@ async fn PageBar(cx: Scope<'_>) -> View { } } - #[component] async fn LoginScreenUI(cx: Scope<'_>) -> View { let app_state = use_context::(cx); @@ -1447,24 +1829,28 @@ async fn LoginScreenUI(cx: Scope<'_>) -> View { let handle_register = move |_| { let app_state = app_state.clone(); - let user = AxumUser{ + let user = AxumUser { id: 0, name: (*userval.get()).clone(), password_hash: (*passval.get()).clone(), }; spawn_local(async move { - let resp = register_user(user) - .await; - //.expect("Couldn't register user"); + let resp = register_user(user).await; + //.expect("Couldn't register user"); if resp.is_err() { - app_state.warningmsg.set("Failed to register user".to_string()); + app_state + .warningmsg + .set("Failed to register user".to_string()); } else { - app_state.warningmsg.set("Successfully registered user".to_string()); + app_state + .warningmsg + .set("Successfully registered user".to_string()); } }); spawn_local(async move { - app_state.userlist.set(list_users() - .await.expect("Couldn't list user")); + app_state + .userlist + .set(list_users().await.expect("Couldn't list user")); }); //app_state.userscreen.set(false); }; @@ -1472,24 +1858,28 @@ async fn LoginScreenUI(cx: Scope<'_>) -> View { let handle_login = move |_| { let app_state = app_state.clone(); let userstr = (*userval.get()).clone(); - let user = AxumUser{ + let user = AxumUser { id: 0, name: (*userval.get()).clone(), password_hash: (*passval.get()).clone(), }; spawn_local(async move { - app_state.userlist.set(list_users() - .await.expect("Couldn't list user")); - login_user(user) - .await.expect("Couldn't login user"); + app_state + .userlist + .set(list_users().await.expect("Couldn't list user")); + login_user(user).await.expect("Couldn't login user"); let auth = authentication_check().await.unwrap_or(false); app_state.loggedin.set(auth); if auth == true { app_state.loggedusername.set(userstr.clone()); app_state.selectedusername.set(userstr.clone()); - 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 + .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); app_state.warningmsg.set("".to_string()); } else { @@ -1504,23 +1894,27 @@ async fn LoginScreenUI(cx: Scope<'_>) -> View { if event.key() == "Enter" { let app_state = app_state.clone(); let userstr = (*userval.get()).clone(); - let user = AxumUser{ + let user = AxumUser { id: 0, name: (*userval.get()).clone(), password_hash: (*passval.get()).clone(), }; spawn_local(async move { - app_state.userlist.set(list_users() - .await.expect("Couldn't list user")); - login_user(user) - .await.expect("Couldn't login user"); + app_state + .userlist + .set(list_users().await.expect("Couldn't list user")); + login_user(user).await.expect("Couldn't login user"); let auth = authentication_check().await.unwrap_or(false); app_state.loggedin.set(auth); if auth == true { app_state.loggedusername.set(userstr.clone()); app_state.selectedusername.set(userstr.clone()); - 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 + .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); app_state.warningmsg.set("".to_string()); } else { @@ -1534,12 +1928,12 @@ async fn LoginScreenUI(cx: Scope<'_>) -> View { if *app_state.userscreen.get() == true { let dom_node = node_ref.try_get::(); if dom_node.is_some() { - dom_node.unwrap().set_attribute("popup-display","true"); + dom_node.unwrap().set_attribute("popup-display", "true"); } } else { let dom_node = node_ref.try_get::(); if dom_node.is_some() { - dom_node.unwrap().set_attribute("popup-display","false"); + dom_node.unwrap().set_attribute("popup-display", "false"); } } }); @@ -1548,23 +1942,21 @@ async fn LoginScreenUI(cx: Scope<'_>) -> View { let dom_node = node_ref.try_get::(); if dom_node.is_some() { - dom_node.unwrap().set_attribute("popup-display","false"); + dom_node.unwrap().set_attribute("popup-display", "false"); } }; - let handle_click_close = |event: Event| { - let target: EventTarget = event.target().unwrap(); - let element: web_sys::Element = target.unchecked_into(); - if element.has_attribute("closable") - { - app_state.userscreen.set(false); + let target: EventTarget = event.target().unwrap(); + let element: web_sys::Element = target.unchecked_into(); + if element.has_attribute("closable") { + app_state.userscreen.set(false); - let dom_node = node_ref.try_get::(); - if dom_node.is_some() { - dom_node.unwrap().set_attribute("popup-display","false"); + let dom_node = node_ref.try_get::(); + if dom_node.is_some() { + dom_node.unwrap().set_attribute("popup-display", "false"); + } } - } }; view! {cx, @@ -1606,7 +1998,6 @@ async fn LoginScreenUI(cx: Scope<'_>) -> View { } } - #[component] fn App(cx: Scope) -> View { let app_state = AppState { @@ -1643,7 +2034,6 @@ fn App(cx: Scope) -> View { }; provide_context(cx, app_state); - view! { cx, div {