neveko/neveko-core/src/product.rs

165 lines
5.1 KiB
Rust

// Product repo/service layer
use crate::{
db,
models::*,
utils,
};
use log::{
debug,
error,
info,
};
use rocket::serde::json::Json;
use std::error::Error;
/// Create a new product
pub fn create(d: Json<Product>) -> Product {
let pid: String = format!("{}{}", crate::PRODUCT_DB_KEY, utils::generate_rnd());
if !validate_product(&d) {
error!("invalid product");
return Default::default();
}
let new_product = Product {
pid: String::from(&pid),
description: String::from(&d.description),
image: d.image.iter().cloned().collect(),
in_stock: d.in_stock,
name: String::from(&d.name),
price: d.price,
qty: d.qty,
};
debug!("insert product: {:?}", &new_product);
let s = db::Interface::open();
let k = &new_product.pid;
db::Interface::write(&s.env, &s.handle, k, &Product::to_db(&new_product));
// in order to retrieve all products, write keys to with pl
let list_key = crate::PRODUCT_LIST_DB_KEY;
let r = db::Interface::read(&s.env, &s.handle, &String::from(list_key));
if r == utils::empty_string() {
debug!("creating product index");
}
let product_list = [r, String::from(&pid)].join(",");
debug!(
"writing product index {} for id: {}",
product_list, list_key
);
db::Interface::write(&s.env, &s.handle, &String::from(list_key), &product_list);
new_product
}
/// Single Product lookup
pub fn find(pid: &String) -> Product {
let s = db::Interface::open();
let r = db::Interface::read(&s.env, &s.handle, &String::from(pid));
if r == utils::empty_string() {
error!("product not found");
return Default::default();
}
Product::from_db(String::from(pid), r)
}
/// Product lookup for all
pub fn find_all() -> Vec<Product> {
let i_s = db::Interface::open();
let i_list_key = crate::PRODUCT_LIST_DB_KEY;
let i_r = db::Interface::read(&i_s.env, &i_s.handle, &String::from(i_list_key));
if i_r == utils::empty_string() {
error!("product index not found");
}
let i_v_pid = i_r.split(",");
let i_v: Vec<String> = i_v_pid.map(|s| String::from(s)).collect();
let mut products: Vec<Product> = Vec::new();
for p in i_v {
let mut product: Product = find(&p);
if product.pid != utils::empty_string() {
// don't return images
product.image = Vec::new();
products.push(product);
}
}
products
}
/// Modify product
pub fn modify(p: Json<Product>) -> Product {
// TODO(c2m): don't allow modification to products with un-delivered orders
info!("modify product: {}", &p.pid);
let f_prod: Product = find(&p.pid);
if f_prod.pid == utils::empty_string() {
error!("product not found");
return Default::default();
}
let u_prod = Product::update(f_prod, &p);
let s = db::Interface::open();
db::Interface::delete(&s.env, &s.handle, &u_prod.pid);
db::Interface::write(&s.env, &s.handle, &u_prod.pid, &Product::to_db(&u_prod));
return u_prod;
}
/// check product field lengths to prevent db spam
fn validate_product(p: &Json<Product>) -> bool {
info!("validating product: {}", &p.pid);
p.pid.len() < utils::string_limit()
&& p.description.len() < utils::string_limit()
&& p.name.len() < utils::string_limit()
&& p.image.len() < utils::image_limit()
}
/// Send the request to vendor for the products available
pub async fn get_vendor_products(
contact: String,
jwp: String,
) -> Result<Vec<Product>, Box<dyn Error>> {
let host = utils::get_i2p_http_proxy();
let proxy = reqwest::Proxy::http(&host)?;
let client = reqwest::Client::builder().proxy(proxy).build();
match client?
.get(format!("http://{}/market/products", contact))
.header("proof", jwp)
.send()
.await
{
Ok(response) => {
let res = response.json::<Vec<Product>>().await;
debug!("get vendor products response: {:?}", res);
match res {
Ok(r) => Ok(r),
_ => Ok(Default::default()),
}
}
Err(e) => {
error!("failed to fetch products due to: {:?}", e);
Ok(Default::default())
}
}
}
/// Send the request to vendor a single product
pub async fn get_vendor_product(
contact: String,
jwp: String,
pid: String,
) -> Result<Product, Box<dyn Error>> {
let host = utils::get_i2p_http_proxy();
let proxy = reqwest::Proxy::http(&host)?;
let client = reqwest::Client::builder().proxy(proxy).build();
match client?
.get(format!("http://{}/market/{}", contact, pid))
.header("proof", jwp)
.send()
.await
{
Ok(response) => {
let res = response.json::<Product>().await;
debug!("get vendor product response: {:?}", res);
match res {
Ok(r) => Ok(r),
_ => Ok(Default::default()),
}
}
Err(e) => {
error!("failed to fetch product due to: {:?}", e);
Ok(Default::default())
}
}
}