feat: new book price in database and book data endpoints
This commit is contained in:
parent
3320d1400c
commit
eb3181242b
6 changed files with 28 additions and 60 deletions
|
|
@ -25,5 +25,5 @@ rand_core = { version = "0.9.3", features = ["os_rng"] }
|
||||||
password-hash = { version = "0.5.0", features = ["getrandom"] }
|
password-hash = { version = "0.5.0", features = ["getrandom"] }
|
||||||
jsonwebtoken = "9.3.1"
|
jsonwebtoken = "9.3.1"
|
||||||
openssl = { version = "0.10.73", features = ["vendored"] }
|
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"] }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,8 @@ pub struct Model {
|
||||||
pub id: u32,
|
pub id: u32,
|
||||||
pub ean: String,
|
pub ean: String,
|
||||||
pub title: String,
|
pub title: String,
|
||||||
pub author: String
|
pub author: String,
|
||||||
|
pub price_new: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Model {
|
impl Default for Model {
|
||||||
|
|
@ -18,7 +19,8 @@ impl Default for Model {
|
||||||
id: 0,
|
id: 0,
|
||||||
ean: "".to_string(),
|
ean: "".to_string(),
|
||||||
title: "".to_string(),
|
title: "".to_string(),
|
||||||
author: "".to_string()
|
author: "".to_string(),
|
||||||
|
price_new: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,12 +57,12 @@ struct BookByEanParams(String);
|
||||||
security(("jwt" = [])),
|
security(("jwt" = [])),
|
||||||
responses(
|
responses(
|
||||||
(status = OK, body = book::Model, description = "Found book with corresponding EAN", examples(
|
(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",
|
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"
|
tag = "book-api"
|
||||||
)]
|
)]
|
||||||
pub async fn get_book_by_ean(
|
pub async fn get_book_by_ean(
|
||||||
|
|
@ -79,7 +79,8 @@ pub async fn get_book_by_ean(
|
||||||
id: res.last_insert_id,
|
id: res.last_insert_id,
|
||||||
ean: ean,
|
ean: ean,
|
||||||
title: book.title,
|
title: book.title,
|
||||||
author: book.author
|
author: book.author,
|
||||||
|
price_new: book.price_new
|
||||||
})))
|
})))
|
||||||
} else {
|
} else {
|
||||||
(StatusCode::NOT_FOUND, Json(None))
|
(StatusCode::NOT_FOUND, Json(None))
|
||||||
|
|
@ -120,6 +121,7 @@ pub async fn create_book(
|
||||||
ean: Set(instance_payload.ean),
|
ean: Set(instance_payload.ean),
|
||||||
title: Set(instance_payload.title),
|
title: Set(instance_payload.title),
|
||||||
author: Set(instance_payload.author),
|
author: Set(instance_payload.author),
|
||||||
|
price_new: Set(None),
|
||||||
id: NotSet
|
id: NotSet
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
use reqwest::StatusCode;
|
use reqwest::StatusCode;
|
||||||
use sea_orm::ActiveValue::{NotSet, Set};
|
use sea_orm::ActiveValue::{NotSet, Set};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde_json::Value;
|
|
||||||
|
|
||||||
use crate::entities::book;
|
use crate::entities::book;
|
||||||
|
|
||||||
|
|
@ -10,13 +9,13 @@ pub struct Response {
|
||||||
#[serde(rename = "numberOfRecords")]
|
#[serde(rename = "numberOfRecords")]
|
||||||
records_number: u32,
|
records_number: u32,
|
||||||
#[serde(rename = "records")]
|
#[serde(rename = "records")]
|
||||||
records: Vec<RecordListElement>
|
records: RecordListElement
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct RecordListElement {
|
pub struct RecordListElement {
|
||||||
#[serde(rename = "record")]
|
#[serde(default, rename = "record")]
|
||||||
record: Record
|
record: Vec<Record>
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
|
|
@ -33,7 +32,7 @@ pub struct RecordData {
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct RecordDataFields {
|
pub struct RecordDataFields {
|
||||||
#[serde(rename = "datafield")]
|
#[serde(default, rename = "datafield")]
|
||||||
datafields: Vec<DataField>
|
datafields: Vec<DataField>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -41,7 +40,7 @@ pub struct RecordDataFields {
|
||||||
pub struct DataField {
|
pub struct DataField {
|
||||||
#[serde(rename = "@tag")]
|
#[serde(rename = "@tag")]
|
||||||
tag: String,
|
tag: String,
|
||||||
#[serde(rename = "subfield")]
|
#[serde(default, rename = "subfield")]
|
||||||
subfields: Vec<SubField>
|
subfields: Vec<SubField>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -57,7 +56,8 @@ pub struct SubField {
|
||||||
pub struct FetchedBook {
|
pub struct FetchedBook {
|
||||||
pub ean: String,
|
pub ean: String,
|
||||||
pub title: String,
|
pub title: String,
|
||||||
pub author: String
|
pub author: String,
|
||||||
|
pub price_new: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FetchedBook {
|
impl FetchedBook {
|
||||||
|
|
@ -66,7 +66,8 @@ impl FetchedBook {
|
||||||
id: NotSet,
|
id: NotSet,
|
||||||
ean: Set(self.ean.clone()),
|
ean: Set(self.ean.clone()),
|
||||||
title: Set(self.title.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");
|
log::debug!(target: "api", "BNF returned 0 records for fetch");
|
||||||
return None;
|
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 {
|
Some(FetchedBook {
|
||||||
ean: ean.to_string(),
|
ean: ean.to_string(),
|
||||||
title: data_dubfield.iter().find(|p| p.code == "a").unwrap().value.clone(),
|
title: data_dubfield.iter().find(|p| p.code == "a").unwrap().value.clone(),
|
||||||
author: data_dubfield.iter().find(|p| p.code == "f").unwrap().value.clone(),
|
author: data_dubfield.iter().find(|p| p.code == "f").unwrap().value.clone(),
|
||||||
|
price_new,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,5 @@ pub mod auth;
|
||||||
pub mod bnf;
|
pub mod bnf;
|
||||||
pub mod cli;
|
pub mod cli;
|
||||||
pub mod events;
|
pub mod events;
|
||||||
pub mod open_library;
|
|
||||||
pub mod serde;
|
pub mod serde;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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<FetchedBook> {
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in a new issue