diff --git a/Cargo.toml b/Cargo.toml index 208b10e..e744709 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,5 +25,5 @@ rand_core = { version = "0.9.3", features = ["os_rng"] } password-hash = { version = "0.5.0", features = ["getrandom"] } jsonwebtoken = "9.3.1" openssl = { version = "0.10.73", features = ["vendored"] } -quick-xml = { version = "0.38.1", features = ["serialize"] } +quick-xml = { version = "0.38.1", features = ["serialize", "overlapped-lists"] } diff --git a/src/entities/book.rs b/src/entities/book.rs index 99126b3..be400fb 100644 --- a/src/entities/book.rs +++ b/src/entities/book.rs @@ -9,7 +9,8 @@ pub struct Model { pub id: u32, pub ean: String, pub title: String, - pub author: String + pub author: String, + pub price_new: Option, } impl Default for Model { @@ -18,7 +19,8 @@ impl Default for Model { id: 0, ean: "".to_string(), title: "".to_string(), - author: "".to_string() + author: "".to_string(), + price_new: None, } } } diff --git a/src/routes/book.rs b/src/routes/book.rs index b6328fc..c22d8f1 100644 --- a/src/routes/book.rs +++ b/src/routes/book.rs @@ -57,12 +57,12 @@ struct BookByEanParams(String); security(("jwt" = [])), responses( (status = OK, body = book::Model, description = "Found book with corresponding EAN", examples( - ("Found regular book" = (value = json!({"author": "Pierre Bottero", "ean": "9782700234015", "id": 5642, "title": "Ellana l'envol"}))) + ("Found regular book" = (value = json!({"author": "Pierre Bottero", "ean": "9782700234015", "id": 5642, "title": "Ellana l'envol", "price_new": "16 EUR"}))) )), - (status = NOT_FOUND, description = "No book with this EAN found in the database or on openlibrary") + (status = NOT_FOUND, description = "No book with this EAN found in the database or on the BNF") ), summary = "Get a book by its EAN", - description = "Get a book from its EAN. If it doesn't exist in its database, Alexandria will try to find it using openlibrary.org's API", + description = "Get a book from its EAN. If it doesn't exist in its database, Alexandria will try to find it using the BNF's API", tag = "book-api" )] pub async fn get_book_by_ean( @@ -79,7 +79,8 @@ pub async fn get_book_by_ean( id: res.last_insert_id, ean: ean, title: book.title, - author: book.author + author: book.author, + price_new: book.price_new }))) } else { (StatusCode::NOT_FOUND, Json(None)) @@ -120,6 +121,7 @@ pub async fn create_book( ean: Set(instance_payload.ean), title: Set(instance_payload.title), author: Set(instance_payload.author), + price_new: Set(None), id: NotSet }; diff --git a/src/utils/bnf.rs b/src/utils/bnf.rs index 782bf06..35e4ed2 100644 --- a/src/utils/bnf.rs +++ b/src/utils/bnf.rs @@ -1,7 +1,6 @@ use reqwest::StatusCode; use sea_orm::ActiveValue::{NotSet, Set}; use serde::Deserialize; -use serde_json::Value; use crate::entities::book; @@ -10,13 +9,13 @@ pub struct Response { #[serde(rename = "numberOfRecords")] records_number: u32, #[serde(rename = "records")] - records: Vec + records: RecordListElement } #[derive(Deserialize)] pub struct RecordListElement { - #[serde(rename = "record")] - record: Record + #[serde(default, rename = "record")] + record: Vec } #[derive(Deserialize)] @@ -33,7 +32,7 @@ pub struct RecordData { #[derive(Deserialize)] pub struct RecordDataFields { - #[serde(rename = "datafield")] + #[serde(default, rename = "datafield")] datafields: Vec } @@ -41,7 +40,7 @@ pub struct RecordDataFields { pub struct DataField { #[serde(rename = "@tag")] tag: String, - #[serde(rename = "subfield")] + #[serde(default, rename = "subfield")] subfields: Vec } @@ -57,7 +56,8 @@ pub struct SubField { pub struct FetchedBook { pub ean: String, pub title: String, - pub author: String + pub author: String, + pub price_new: Option, } impl FetchedBook { @@ -66,7 +66,8 @@ impl FetchedBook { id: NotSet, ean: Set(self.ean.clone()), title: Set(self.title.clone()), - author: Set(self.author.clone()) + author: Set(self.author.clone()), + price_new: Set(self.price_new.clone()) } } } @@ -88,11 +89,18 @@ pub async fn fetch_book_by_ean(web_client: &reqwest::Client, ean: &String) -> Op log::debug!(target: "api", "BNF returned 0 records for fetch"); return None; } - let data_dubfield = v.records.first().unwrap().record_data.record.record.datafields.iter().find(|d| d.tag == "200").unwrap().subfields.clone(); + let record = &v.records.record.first().unwrap(); + let data_dubfield = record.record_data.record.datafields.iter().find(|d| d.tag == "200").unwrap().subfields.clone(); + let price_new = match record.record_data.record.datafields.iter().find(|d| d.tag == "010") { + Some(f) => f.subfields.iter().find(|p| p.code=="d").map_or(None, |v| Some(v.value.clone())), + None => None + }; + Some(FetchedBook { ean: ean.to_string(), title: data_dubfield.iter().find(|p| p.code == "a").unwrap().value.clone(), author: data_dubfield.iter().find(|p| p.code == "f").unwrap().value.clone(), + price_new, }) }, Err(e) => { diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 4566cf7..8cb162f 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -2,6 +2,5 @@ pub mod auth; pub mod bnf; pub mod cli; pub mod events; -pub mod open_library; pub mod serde; diff --git a/src/utils/open_library.rs b/src/utils/open_library.rs deleted file mode 100644 index d1b9af1..0000000 --- a/src/utils/open_library.rs +++ /dev/null @@ -1,43 +0,0 @@ -use reqwest::StatusCode; -use sea_orm::ActiveValue::{NotSet, Set}; -use serde_json::Value; - -use crate::entities::book; - -pub struct FetchedBook { - pub ean: String, - pub title: String, - pub author: String -} - -impl FetchedBook { - pub fn to_active_model(&self) -> book::ActiveModel { - book::ActiveModel { - id: NotSet, - ean: Set(self.ean.clone()), - title: Set(self.title.clone()), - author: Set(self.author.clone()) - } - } -} - -pub async fn fetch_book_by_ean(web_client: &reqwest::Client, ean: &String) -> Option { - let body = web_client.execute( - web_client.get(format!("https://openlibrary.org/isbn/{ean}.json")) - .build() - .expect("get request creation failed") - ).await.unwrap(); - match body.status() { - StatusCode::OK => { - let res = body.text().await.unwrap(); - log::trace!(target: "api", "OpenLibrary book fetch result: {res:#?}"); - let v: Value = serde_json::from_str(&res).unwrap(); - Some(FetchedBook { - ean: ean.to_string(), - title: v.get("title").unwrap().to_string(), - author: "temp".to_owned() - }) - }, - _ => None - } -}