mirror of
https://github.com/creating2morrow/neveko.git
synced 2024-12-22 11:39:22 +00:00
add order validations for shipping
This commit is contained in:
parent
3255b15c9a
commit
60786f23d4
7 changed files with 123 additions and 63 deletions
|
@ -236,8 +236,8 @@ pub struct Product {
|
|||
pub image: Vec<u8>,
|
||||
pub in_stock: bool,
|
||||
pub name: String,
|
||||
pub price: i64,
|
||||
pub qty: i64,
|
||||
pub price: u64,
|
||||
pub qty: u64,
|
||||
}
|
||||
|
||||
impl Default for Product {
|
||||
|
@ -272,11 +272,11 @@ impl Product {
|
|||
Err(_) => false,
|
||||
};
|
||||
let name = v.remove(0);
|
||||
let price = match v.remove(0).parse::<i64>() {
|
||||
let price = match v.remove(0).parse::<u64>() {
|
||||
Ok(p) => p,
|
||||
Err(_) => 0,
|
||||
};
|
||||
let qty = match v.remove(0).parse::<i64>() {
|
||||
let qty = match v.remove(0).parse::<u64>() {
|
||||
Ok(q) => q,
|
||||
Err(_) => 0,
|
||||
};
|
||||
|
|
|
@ -4,7 +4,7 @@ use crate::{
|
|||
models::*,
|
||||
monero,
|
||||
reqres,
|
||||
utils,
|
||||
utils, product, gpg, i2p,
|
||||
};
|
||||
use log::{
|
||||
debug,
|
||||
|
@ -15,16 +15,14 @@ use rocket::serde::json::Json;
|
|||
|
||||
/*
|
||||
TODOs(c2m):
|
||||
- API to validate payment and import multisig info, update to multisig complete
|
||||
- API to upload gpg encrypted tracking number, update order to shipped
|
||||
- release tracking (locker code?) when txset is released, update to delivered
|
||||
*/
|
||||
|
||||
enum StatusType {
|
||||
_Delivered,
|
||||
MultisigMissing,
|
||||
_MulitsigComplete,
|
||||
_Shipped,
|
||||
MulitsigComplete,
|
||||
Shipped,
|
||||
}
|
||||
|
||||
impl StatusType {
|
||||
|
@ -32,8 +30,8 @@ impl StatusType {
|
|||
match *self {
|
||||
StatusType::_Delivered => String::from("Delivered"),
|
||||
StatusType::MultisigMissing => String::from("MultisigMissing"),
|
||||
StatusType::_MulitsigComplete => String::from("MulitsigComplete"),
|
||||
StatusType::_Shipped => String::from("Shipped"),
|
||||
StatusType::MulitsigComplete => String::from("MulitsigComplete"),
|
||||
StatusType::Shipped => String::from("Shipped"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -175,7 +173,7 @@ pub async fn sign_and_submit_multisig(
|
|||
/// that the mediator can see order id for disputes without being able to access
|
||||
///
|
||||
/// the details of said order.
|
||||
pub async fn retrieve_order(orid: &String, signature: &String) -> Order {
|
||||
pub async fn secure_retrieval(orid: &String, signature: &String) -> Order {
|
||||
// get customer address for NEVEKO NOT order wallet
|
||||
let m_order: Order = find(&orid);
|
||||
let mut xmr_address: String = String::new();
|
||||
|
@ -183,6 +181,7 @@ pub async fn retrieve_order(orid: &String, signature: &String) -> Order {
|
|||
for customer in a_customers {
|
||||
if customer.i2p_address == m_order.cid {
|
||||
xmr_address = customer.xmr_address;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// send address, orid and signature to verify()
|
||||
|
@ -195,12 +194,57 @@ pub async fn retrieve_order(orid: &String, signature: &String) -> Order {
|
|||
m_order
|
||||
}
|
||||
|
||||
pub async fn validate_order_for_ship() -> bool {
|
||||
/// Check for import multisig info, validate block time and that the
|
||||
///
|
||||
/// order wallet has been funded properly. Update the order to multisig complete
|
||||
pub async fn validate_order_for_ship(orid: &String) -> bool {
|
||||
info!("validating order for shipment");
|
||||
let mut m_order: Order = find(orid);
|
||||
let m_product: Product = product::find(&m_order.pid);
|
||||
let price = m_product.price;
|
||||
let total = price * m_order.quantity;
|
||||
// import multisig info
|
||||
|
||||
let s = db::Interface::open();
|
||||
let key = format!("export-{}-{}", orid, &m_order.cid);
|
||||
let info_str = db::Interface::async_read(&s.env, &s.handle, &key).await;
|
||||
let info_split = info_str.split(":");
|
||||
let v_info: Vec<String> = info_split.map(|s| String::from(s)).collect();
|
||||
let wallet_password = utils::empty_string();
|
||||
monero::open_wallet(&orid, &wallet_password).await;
|
||||
let r_import = monero::import_multisig_info(v_info).await;
|
||||
// check balance and unlock_time
|
||||
|
||||
let r_balance = monero::get_balance().await;
|
||||
// update the order status to multisig complete
|
||||
return false;
|
||||
let ready_to_ship: bool = r_import.result.n_outputs > 0
|
||||
&& r_balance.result.balance >= total as u128
|
||||
&& r_balance.result.blocks_to_unlock < monero::LockTimeLimit::Blocks.value();
|
||||
if ready_to_ship {
|
||||
m_order.status = StatusType::MulitsigComplete.value();
|
||||
db::Interface::async_delete(&s.env, &s.handle, &m_order.orid).await;
|
||||
db::Interface::async_write(&s.env, &s.handle, &m_order.orid, &Order::to_db(&m_order)).await;
|
||||
}
|
||||
ready_to_ship
|
||||
}
|
||||
|
||||
/// Write encrypted delivery info to lmdb. Once the customer releases the signed txset
|
||||
///
|
||||
/// they will have access to this information (tracking number, locker code, etc.)
|
||||
pub async fn upload_delivery_info(orid: &String, delivery_info: &Vec<u8>) {
|
||||
info!("uploading delivery info");
|
||||
let name = i2p::get_destination(None);
|
||||
let e_delivery_info: Vec<u8> = gpg::encrypt(name, &delivery_info)
|
||||
.unwrap_or(Vec::new());
|
||||
if e_delivery_info.is_empty() {
|
||||
error!("unable to encrypt delivery info");
|
||||
}
|
||||
// write delivery info {delivery}-{order id}
|
||||
let s = db::Interface::async_open().await;
|
||||
let k = format!("delivery-{}", orid);
|
||||
let data = hex::encode(e_delivery_info);
|
||||
db::Interface::async_write(&s.env, &s.handle, &k, &data).await;
|
||||
// update the order
|
||||
let mut m_order: Order = find(orid);
|
||||
m_order.status = StatusType::Shipped.value();
|
||||
db::Interface::async_delete(&s.env, &s.handle, &m_order.orid).await;
|
||||
db::Interface::async_write(&s.env, &s.handle, &m_order.orid, &Order::to_db(&m_order)).await;
|
||||
}
|
||||
|
|
|
@ -368,7 +368,7 @@ pub struct SubAddressInfo {
|
|||
pub label: String,
|
||||
pub num_unspent_outputs: u64,
|
||||
pub time_to_unlock: u128,
|
||||
pub blocks_to_unlock: u128,
|
||||
pub blocks_to_unlock: u64,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
|
@ -391,7 +391,7 @@ pub struct XmrRpcBalanceResult {
|
|||
pub unlocked_balance: u128,
|
||||
pub multisig_import_needed: bool,
|
||||
pub time_to_unlock: u128,
|
||||
pub blocks_to_unlock: u128,
|
||||
pub blocks_to_unlock: u64,
|
||||
pub per_subaddress: Vec<SubAddressInfo>,
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ pub const LOCK_SCREEN_TIMEOUT_SECS: u64 = 60 * 5;
|
|||
/// interval to search for credential on initial gui load
|
||||
pub const CRED_CHECK_INTERVAL: u64 = 5;
|
||||
/// monero estimated block time in seconds
|
||||
pub const BLOCK_TIME_IN_SECS_EST: u128 = 0x78;
|
||||
pub const BLOCK_TIME_IN_SECS_EST: u64 = 0x78;
|
||||
/// time to wait before giving up on adding a contact
|
||||
pub const ADD_CONTACT_TIMEOUT_SECS: u64 = 0x5A;
|
||||
/// time to wait before giving up on neveko core
|
||||
|
|
|
@ -52,7 +52,7 @@ pub async fn get_order(orid: String, _token: auth::BearerToken) -> Custom<Json<m
|
|||
Custom(Status::Ok, Json(m_order))
|
||||
}
|
||||
|
||||
/// Get a order by passing id
|
||||
/// Get all orders
|
||||
#[get("/")]
|
||||
pub async fn get_orders(_token: auth::BearerToken) -> Custom<Json<Vec<models::Order>>> {
|
||||
let m_orders: Vec<models::Order> = order::find_all();
|
||||
|
@ -86,7 +86,7 @@ pub async fn get_dispute(_token: auth::BearerToken, did: String) -> Custom<Json<
|
|||
Custom(Status::Ok, Json(m_dispute))
|
||||
}
|
||||
|
||||
/// Create a dispute
|
||||
/// Sign and submit multisig
|
||||
#[post("/sign/submit", data = "<r_data>")]
|
||||
pub async fn sign_and_submit_multisig(
|
||||
r_data: Json<reqres::SignAndSubmitRequest>,
|
||||
|
|
|
@ -3,7 +3,7 @@ use rocket::{
|
|||
http::Status,
|
||||
post,
|
||||
response::status::Custom,
|
||||
serde::json::Json,
|
||||
serde::json::Json, catch,
|
||||
};
|
||||
|
||||
use neveko_core::*;
|
||||
|
@ -109,7 +109,7 @@ pub async fn retrieve_order(
|
|||
signature: String,
|
||||
_jwp: proof::PaymentProof,
|
||||
) -> Custom<Json<models::Order>> {
|
||||
let m_order = order::retrieve_order(&orid, &signature).await;
|
||||
let m_order = order::secure_retrieval(&orid, &signature).await;
|
||||
if m_order.cid == utils::empty_string() {
|
||||
return Custom(Status::BadRequest, Json(Default::default()));
|
||||
}
|
||||
|
@ -156,8 +156,55 @@ pub async fn rx_multisig_message(
|
|||
/// multisig info, check balance and sanity check `unlock_time`.
|
||||
///
|
||||
/// Protected: true
|
||||
#[post("/")]
|
||||
pub async fn request_shipment(_jwp: proof::PaymentProof) -> Custom<Json<models::Message>> {
|
||||
order::validate_order_for_ship().await;
|
||||
#[post("/<orid>")]
|
||||
pub async fn request_shipment(orid: String, _jwp: proof::PaymentProof) -> Custom<Json<models::Message>> {
|
||||
let is_ready: bool = order::validate_order_for_ship(&orid).await;
|
||||
if !is_ready {
|
||||
return Custom(Status::BadRequest, Json(Default::default()));
|
||||
}
|
||||
Custom(Status::Ok, Json(Default::default()))
|
||||
}
|
||||
|
||||
/// Create a dispute (customer)
|
||||
#[post("/create", data = "<dispute>")]
|
||||
pub async fn create_dispute(
|
||||
dispute: Json<models::Dispute>,
|
||||
_token: auth::BearerToken,
|
||||
) -> Custom<Json<models::Dispute>> {
|
||||
let m_dispute: models::Dispute = dispute::create(dispute);
|
||||
Custom(Status::Ok, Json(m_dispute))
|
||||
}
|
||||
|
||||
|
||||
// Catchers
|
||||
//----------------------------------------------------------------
|
||||
|
||||
#[catch(402)]
|
||||
pub fn payment_required() -> Custom<Json<reqres::ErrorResponse>> {
|
||||
Custom(
|
||||
Status::PaymentRequired,
|
||||
Json(reqres::ErrorResponse {
|
||||
error: String::from("Payment required"),
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
#[catch(404)]
|
||||
pub fn not_found() -> Custom<Json<reqres::ErrorResponse>> {
|
||||
Custom(
|
||||
Status::NotFound,
|
||||
Json(reqres::ErrorResponse {
|
||||
error: String::from("Resource does not exist"),
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
#[catch(500)]
|
||||
pub fn internal_error() -> Custom<Json<reqres::ErrorResponse>> {
|
||||
Custom(
|
||||
Status::InternalServerError,
|
||||
Json(reqres::ErrorResponse {
|
||||
error: String::from("Internal server error"),
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
|
43
src/main.rs
43
src/main.rs
|
@ -1,44 +1,9 @@
|
|||
#[macro_use]
|
||||
extern crate rocket;
|
||||
use rocket::{
|
||||
http::Status,
|
||||
response::status::Custom,
|
||||
serde::json::Json,
|
||||
};
|
||||
|
||||
use neveko::*;
|
||||
use neveko_core::*;
|
||||
|
||||
#[catch(402)]
|
||||
fn payment_required() -> Custom<Json<reqres::ErrorResponse>> {
|
||||
Custom(
|
||||
Status::PaymentRequired,
|
||||
Json(reqres::ErrorResponse {
|
||||
error: String::from("Payment required"),
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
#[catch(404)]
|
||||
fn not_found() -> Custom<Json<reqres::ErrorResponse>> {
|
||||
Custom(
|
||||
Status::NotFound,
|
||||
Json(reqres::ErrorResponse {
|
||||
error: String::from("Resource does not exist"),
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
#[catch(500)]
|
||||
fn internal_error() -> Custom<Json<reqres::ErrorResponse>> {
|
||||
Custom(
|
||||
Status::InternalServerError,
|
||||
Json(reqres::ErrorResponse {
|
||||
error: String::from("Internal server error"),
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
// The only changes below here should be mounting new controller methods
|
||||
#[launch]
|
||||
async fn rocket() -> _ {
|
||||
|
@ -51,7 +16,11 @@ async fn rocket() -> _ {
|
|||
env_logger::init();
|
||||
utils::start_up().await;
|
||||
rocket::custom(&config)
|
||||
.register("/", catchers![internal_error, not_found, payment_required])
|
||||
.register("/", catchers![
|
||||
controller::internal_error,
|
||||
controller::not_found,
|
||||
controller::payment_required
|
||||
])
|
||||
.mount("/multisig/info", routes![controller::get_multisig_info])
|
||||
.mount("/invoice", routes![controller::gen_invoice])
|
||||
.mount("/message/rx", routes![controller::rx_message])
|
||||
|
@ -65,6 +34,6 @@ async fn rocket() -> _ {
|
|||
.mount("/xmr/rpc", routes![controller::get_version])
|
||||
.mount(
|
||||
"/market",
|
||||
routes![controller::create_order, controller::get_products],
|
||||
routes![controller::create_order, controller::get_products, controller::create_dispute],
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue