implement requirements for ordering server
This commit is contained in:
		@@ -4,7 +4,7 @@ pub mod models;
 | 
			
		||||
use self::models::{Boot, Rescue, Server, SshKey};
 | 
			
		||||
use crate::api::error::ApiError;
 | 
			
		||||
use crate::api::models::{
 | 
			
		||||
    BootWrapper, Cancellation, CancellationWrapper, RescueWrapped, ServerWrapper, SshKeyWrapper,
 | 
			
		||||
    BootWrapper, Cancellation, CancellationWrapper, OrderServerProduct, OrderServerProductWrapper, RescueWrapped, ServerWrapper, SshKeyWrapper
 | 
			
		||||
};
 | 
			
		||||
use crate::config::Config;
 | 
			
		||||
use error::AppError;
 | 
			
		||||
@@ -244,4 +244,16 @@ impl Client {
 | 
			
		||||
        let wrapped: RescueWrapped = self.handle_response(response)?;
 | 
			
		||||
        Ok(wrapped.rescue)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn get_server_ordering_product_overview(&self) -> Result<Vec<OrderServerProduct>, AppError> {
 | 
			
		||||
        let response = self
 | 
			
		||||
            .http_client
 | 
			
		||||
            .get(format!("{}/order/server/product", &self.config.api_url))
 | 
			
		||||
            .basic_auth(&self.config.username, Some(&self.config.password))
 | 
			
		||||
            .send()?;
 | 
			
		||||
 | 
			
		||||
        let wrapped: Vec<OrderServerProductWrapper> = self.handle_response(response)?;
 | 
			
		||||
        let products = wrapped.into_iter().map(|sop| sop.product).collect();
 | 
			
		||||
        Ok(products)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -648,4 +648,190 @@ impl From<reqwest::blocking::Response> for ApiError {
 | 
			
		||||
            message: value.text().unwrap_or("The API call returned an error.".to_string()),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Deserialize, Clone, CustomType)]
 | 
			
		||||
#[rhai_type(extra = Self::build_rhai_type)]
 | 
			
		||||
pub struct Price {
 | 
			
		||||
    pub net: String,
 | 
			
		||||
    pub gross: String,
 | 
			
		||||
    pub hourly_net: String,
 | 
			
		||||
    pub hourly_gross: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Price {
 | 
			
		||||
    fn build_rhai_type(builder: &mut TypeBuilder<Self>) {
 | 
			
		||||
        builder
 | 
			
		||||
            .with_name("Price")
 | 
			
		||||
            .with_get("net", |p: &mut Price| p.net.clone())
 | 
			
		||||
            .with_get("gross", |p: &mut Price| p.gross.clone())
 | 
			
		||||
            .with_get("hourly_net", |p: &mut Price| p.hourly_net.clone())
 | 
			
		||||
            .with_get("hourly_gross", |p: &mut Price| p.hourly_gross.clone())
 | 
			
		||||
            .on_print(|p: &mut Price| p.to_string())
 | 
			
		||||
            .with_fn("pretty_print", |p: &mut Price| p.to_string());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl fmt::Display for Price {
 | 
			
		||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
			
		||||
        write!(
 | 
			
		||||
            f,
 | 
			
		||||
            "Net: {}, Gross: {}, Hourly Net: {}, Hourly Gross: {}",
 | 
			
		||||
            self.net, self.gross, self.hourly_net, self.hourly_gross
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Deserialize, Clone, CustomType)]
 | 
			
		||||
#[rhai_type(extra = Self::build_rhai_type)]
 | 
			
		||||
pub struct PriceSetup {
 | 
			
		||||
    pub net: String,
 | 
			
		||||
    pub gross: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl PriceSetup {
 | 
			
		||||
    fn build_rhai_type(builder: &mut TypeBuilder<Self>) {
 | 
			
		||||
        builder
 | 
			
		||||
            .with_name("PriceSetup")
 | 
			
		||||
            .with_get("net", |p: &mut PriceSetup| p.net.clone())
 | 
			
		||||
            .with_get("gross", |p: &mut PriceSetup| p.gross.clone())
 | 
			
		||||
            .on_print(|p: &mut PriceSetup| p.to_string())
 | 
			
		||||
            .with_fn("pretty_print", |p: &mut PriceSetup| p.to_string());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl fmt::Display for PriceSetup {
 | 
			
		||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
			
		||||
        write!(f, "Net: {}, Gross: {}", self.net, self.gross)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Deserialize, Clone, CustomType)]
 | 
			
		||||
#[rhai_type(extra = Self::build_rhai_type)]
 | 
			
		||||
pub struct ProductPrice {
 | 
			
		||||
    pub location: String,
 | 
			
		||||
    pub price: Price,
 | 
			
		||||
    pub price_setup: PriceSetup,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl ProductPrice {
 | 
			
		||||
    fn build_rhai_type(builder: &mut TypeBuilder<Self>) {
 | 
			
		||||
        builder
 | 
			
		||||
            .with_name("ProductPrice")
 | 
			
		||||
            .with_get("location", |p: &mut ProductPrice| p.location.clone())
 | 
			
		||||
            .with_get("price", |p: &mut ProductPrice| p.price.clone())
 | 
			
		||||
            .with_get("price_setup", |p: &mut ProductPrice| p.price_setup.clone())
 | 
			
		||||
            .on_print(|p: &mut ProductPrice| p.to_string())
 | 
			
		||||
            .with_fn("pretty_print", |p: &mut ProductPrice| p.to_string());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl fmt::Display for ProductPrice {
 | 
			
		||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
			
		||||
        write!(
 | 
			
		||||
            f,
 | 
			
		||||
            "Location: {}, Price: ({}), Price Setup: ({})",
 | 
			
		||||
            self.location, self.price, self.price_setup
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Deserialize, Clone, CustomType)]
 | 
			
		||||
#[rhai_type(extra = Self::build_rhai_type)]
 | 
			
		||||
pub struct OrderableAddon {
 | 
			
		||||
    pub id: String,
 | 
			
		||||
    pub name: String,
 | 
			
		||||
    pub min: i32,
 | 
			
		||||
    pub max: i32,
 | 
			
		||||
    pub prices: Vec<ProductPrice>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl OrderableAddon {
 | 
			
		||||
    fn build_rhai_type(builder: &mut TypeBuilder<Self>) {
 | 
			
		||||
        builder
 | 
			
		||||
            .with_name("OrderableAddon")
 | 
			
		||||
            .with_get("id", |o: &mut OrderableAddon| o.id.clone())
 | 
			
		||||
            .with_get("name", |o: &mut OrderableAddon| o.name.clone())
 | 
			
		||||
            .with_get("min", |o: &mut OrderableAddon| o.min)
 | 
			
		||||
            .with_get("max", |o: &mut OrderableAddon| o.max)
 | 
			
		||||
            .with_get("prices", |o: &mut OrderableAddon| o.prices.clone())
 | 
			
		||||
            .on_print(|o: &mut OrderableAddon| o.to_string())
 | 
			
		||||
            .with_fn("pretty_print", |o: &mut OrderableAddon| o.to_string());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl fmt::Display for OrderableAddon {
 | 
			
		||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
			
		||||
        let mut table = Table::new();
 | 
			
		||||
        table.add_row(row!["Property", "Value"]);
 | 
			
		||||
        table.add_row(row!["ID", self.id.clone()]);
 | 
			
		||||
        table.add_row(row!["Name", self.name.clone()]);
 | 
			
		||||
        table.add_row(row!["Min", self.min.to_string()]);
 | 
			
		||||
        table.add_row(row!["Max", self.max.to_string()]);
 | 
			
		||||
        table.add_row(row!["Prices", format!("{:?}", self.prices)]);
 | 
			
		||||
        write!(f, "{}", table)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Deserialize, Clone)]
 | 
			
		||||
pub struct OrderServerProductWrapper {
 | 
			
		||||
    pub product: OrderServerProduct,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Deserialize, Clone, CustomType)]
 | 
			
		||||
#[rhai_type(extra = Self::build_rhai_type)]
 | 
			
		||||
pub struct OrderServerProduct {
 | 
			
		||||
    pub id: String,
 | 
			
		||||
    pub name: String,
 | 
			
		||||
    #[serde(deserialize_with = "string_or_seq_string")]
 | 
			
		||||
    pub description: Vec<String>,
 | 
			
		||||
    pub traffic: String,
 | 
			
		||||
    #[serde(deserialize_with = "string_or_seq_string")]
 | 
			
		||||
    pub dist: Vec<String>,
 | 
			
		||||
    #[serde(rename = "@deprecated arch", default, deserialize_with = "option_string_or_seq_string")]
 | 
			
		||||
    #[deprecated(note = "use `dist` instead")]
 | 
			
		||||
    pub arch: Option<Vec<String>>,
 | 
			
		||||
    #[serde(deserialize_with = "string_or_seq_string")]
 | 
			
		||||
    pub lang: Vec<String>,
 | 
			
		||||
    #[serde(deserialize_with = "string_or_seq_string")]
 | 
			
		||||
    pub location: Vec<String>,
 | 
			
		||||
    pub prices: Vec<ProductPrice>,
 | 
			
		||||
    pub orderable_addons: Vec<OrderableAddon>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl OrderServerProduct {
 | 
			
		||||
    fn build_rhai_type(builder: &mut TypeBuilder<Self>) {
 | 
			
		||||
        builder
 | 
			
		||||
            .with_name("OrderServerProduct")
 | 
			
		||||
            .with_get("id", |o: &mut OrderServerProduct| o.id.clone())
 | 
			
		||||
            .with_get("name", |o: &mut OrderServerProduct| o.name.clone())
 | 
			
		||||
            .with_get("description", |o: &mut OrderServerProduct| o.description.clone())
 | 
			
		||||
            .with_get("traffic", |o: &mut OrderServerProduct| o.traffic.clone())
 | 
			
		||||
            .with_get("dist", |o: &mut OrderServerProduct| o.dist.clone())
 | 
			
		||||
            .with_get("arch", |o: &mut OrderServerProduct| o.arch.clone())
 | 
			
		||||
            .with_get("lang", |o: &mut OrderServerProduct| o.lang.clone())
 | 
			
		||||
            .with_get("location", |o: &mut OrderServerProduct| o.location.clone())
 | 
			
		||||
            .with_get("prices", |o: &mut OrderServerProduct| o.prices.clone())
 | 
			
		||||
            .with_get("orderable_addons", |o: &mut OrderServerProduct| o.orderable_addons.clone())
 | 
			
		||||
            .on_print(|o: &mut OrderServerProduct| o.to_string())
 | 
			
		||||
            .with_fn("pretty_print", |o: &mut OrderServerProduct| o.to_string());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl fmt::Display for OrderServerProduct {
 | 
			
		||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
			
		||||
        let mut table = Table::new();
 | 
			
		||||
        table.add_row(row!["Property", "Value"]);
 | 
			
		||||
        table.add_row(row!["ID", self.id.clone()]);
 | 
			
		||||
        table.add_row(row!["Name", self.name.clone()]);
 | 
			
		||||
        table.add_row(row!["Description", self.description.join(", ")]);
 | 
			
		||||
        table.add_row(row!["Traffic", self.traffic.clone()]);
 | 
			
		||||
        table.add_row(row!["Distributions", self.dist.join(", ")]);
 | 
			
		||||
        table.add_row(row!["Architectures", self.arch.as_deref().unwrap_or_default().join(", ")]);
 | 
			
		||||
        table.add_row(row!["Languages", self.lang.join(", ")]);
 | 
			
		||||
        table.add_row(row!["Locations", self.location.join(", ")]);
 | 
			
		||||
        table.add_row(row!["Prices", format!("{:?}", self.prices)]);
 | 
			
		||||
        table.add_row(row!["Orderable Addons", format!("{:?}", self.orderable_addons)]);
 | 
			
		||||
        write!(f, "{}", table)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,11 +1,12 @@
 | 
			
		||||
use crate::api::Client;
 | 
			
		||||
use crate::api::models::{Rescue, Linux, Vnc, Windows, Plesk, Cpanel, Boot, Server, SshKey, Cancellation};
 | 
			
		||||
use crate::api::models::{Rescue, Linux, Vnc, Windows, Plesk, Cpanel, Boot, Server, SshKey, Cancellation, OrderServerProduct};
 | 
			
		||||
use rhai::{Engine, Scope};
 | 
			
		||||
 | 
			
		||||
pub mod server;
 | 
			
		||||
pub mod ssh_keys;
 | 
			
		||||
pub mod boot;
 | 
			
		||||
pub mod printing;
 | 
			
		||||
pub mod server_ordering;
 | 
			
		||||
 | 
			
		||||
pub fn setup_engine(client: Client) -> (Engine, Scope<'static>) {
 | 
			
		||||
    let mut engine = Engine::new();
 | 
			
		||||
@@ -21,11 +22,13 @@ pub fn setup_engine(client: Client) -> (Engine, Scope<'static>) {
 | 
			
		||||
    engine.build_type::<Plesk>();
 | 
			
		||||
    engine.build_type::<Cpanel>();
 | 
			
		||||
    engine.build_type::<Cancellation>();
 | 
			
		||||
    engine.build_type::<OrderServerProduct>();
 | 
			
		||||
 | 
			
		||||
    server::register(&mut engine);
 | 
			
		||||
    ssh_keys::register(&mut engine);
 | 
			
		||||
    boot::register(&mut engine);
 | 
			
		||||
    printing::register(&mut engine);
 | 
			
		||||
    server_ordering::register(&mut engine);
 | 
			
		||||
 | 
			
		||||
    scope.push("hetzner", client);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,11 @@
 | 
			
		||||
use rhai::{Array, Engine};
 | 
			
		||||
use crate::scripting::{Server, SshKey};
 | 
			
		||||
use crate::{api::models::OrderServerProduct, scripting::{Server, SshKey}};
 | 
			
		||||
 | 
			
		||||
mod servers_table;
 | 
			
		||||
mod ssh_keys_table;
 | 
			
		||||
mod server_ordering_table;
 | 
			
		||||
 | 
			
		||||
// This will be called when we print(...) or pretty_print() an Array (with Dynamic values)
 | 
			
		||||
pub fn pretty_print_dispatch(array: Array) {
 | 
			
		||||
    println!("pretty print dispatch");
 | 
			
		||||
    if array.is_empty() {
 | 
			
		||||
@@ -17,6 +19,9 @@ pub fn pretty_print_dispatch(array: Array) {
 | 
			
		||||
        servers_table::pretty_print_servers(array);
 | 
			
		||||
    } else if first.is::<SshKey>() {
 | 
			
		||||
        ssh_keys_table::pretty_print_ssh_keys(array);
 | 
			
		||||
    }
 | 
			
		||||
    else if first.is::<OrderServerProduct>() {
 | 
			
		||||
        server_ordering_table::pretty_print_server_products(array);
 | 
			
		||||
    } else {
 | 
			
		||||
        // Generic fallback for other types
 | 
			
		||||
        for item in array {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										38
									
								
								src/scripting/printing/server_ordering_table.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								src/scripting/printing/server_ordering_table.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,38 @@
 | 
			
		||||
use prettytable::{row, Table};
 | 
			
		||||
use crate::api::models::OrderServerProduct;
 | 
			
		||||
 | 
			
		||||
pub fn pretty_print_server_products(products: rhai::Array) {
 | 
			
		||||
    let mut table = Table::new();
 | 
			
		||||
    table.add_row(row![b =>
 | 
			
		||||
        "ID",
 | 
			
		||||
        "Name",
 | 
			
		||||
        "Description",
 | 
			
		||||
        "Traffic",
 | 
			
		||||
        "Location",
 | 
			
		||||
        "Price (Net)",
 | 
			
		||||
        "Price (Gross)",
 | 
			
		||||
    ]);
 | 
			
		||||
 | 
			
		||||
    for product_dyn in products {
 | 
			
		||||
        if let Some(product) = product_dyn.try_cast::<OrderServerProduct>() {
 | 
			
		||||
            let mut price_net = "N/A".to_string();
 | 
			
		||||
            let mut price_gross = "N/A".to_string();
 | 
			
		||||
 | 
			
		||||
            if let Some(first_price) = product.prices.first() {
 | 
			
		||||
                price_net = first_price.price.net.clone();
 | 
			
		||||
                price_gross = first_price.price.gross.clone();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            table.add_row(row![
 | 
			
		||||
                product.id,
 | 
			
		||||
                product.name,
 | 
			
		||||
                product.description.join(", "),
 | 
			
		||||
                product.traffic,
 | 
			
		||||
                product.location.join(", "),
 | 
			
		||||
                price_net,
 | 
			
		||||
                price_gross,
 | 
			
		||||
            ]);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    table.printstd();
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										23
									
								
								src/scripting/server_ordering.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/scripting/server_ordering.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
			
		||||
use crate::api::{Client, models::OrderServerProduct};
 | 
			
		||||
use rhai::{Array, Dynamic, plugin::*};
 | 
			
		||||
 | 
			
		||||
pub fn register(engine: &mut Engine) {
 | 
			
		||||
    let server_order_module = exported_module!(server_order_api);
 | 
			
		||||
    engine.register_global_module(server_order_module.into());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[export_module]
 | 
			
		||||
pub mod server_order_api {
 | 
			
		||||
    // use super::*;
 | 
			
		||||
    // use rhai::EvalAltResult;
 | 
			
		||||
 | 
			
		||||
    #[rhai_fn(name = "get_server_ordering_product_overview", return_raw)]
 | 
			
		||||
    pub fn get_server_ordering_product_overview(
 | 
			
		||||
        client: &mut Client,
 | 
			
		||||
    ) -> Result<Array, Box<EvalAltResult>> {
 | 
			
		||||
        let overview_servers = client
 | 
			
		||||
            .get_server_ordering_product_overview()
 | 
			
		||||
            .map_err(|e| Into::<Box<EvalAltResult>>::into(e.to_string()))?;
 | 
			
		||||
        Ok(overview_servers.into_iter().map(Dynamic::from).collect())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user