added functions check auctioned transactions and order auctioned server

This commit is contained in:
Maxime Van Hees 2025-07-22 17:34:17 +02:00
parent 2e999a3e7e
commit a92b896d17
8 changed files with 724 additions and 25 deletions

View File

@ -1,15 +1,48 @@
// // Get all available products (servers) that we can order and print them in a table
/// --- Get all available products (servers) that we can order and print them in a table
// let available_server_products = hetzner.get_server_ordering_product_overview();
// available_server_products.pretty_print();
// // List the details from a specific sever product based on the ID
/// --- List the details from a specific sever product based on the ID
// let example_server_product = hetzner.get_server_ordering_product_by_id("AX41-NVMe");
// print(example_server_product);
// List all the transactions from the past 30 days
/// --- List all the transactions from the past 30 days
// let transactions_last_30 = hetzner.get_transactions();
// print(transactions_last_30);
let example_transaction = hetzner.get_transaction_by_id("2111181");
print(example_transaction);
/// --- Fetch a transcation by ID
// let example_transaction = hetzner.get_transaction_by_id("120000706572");
// print(example_transaction);
/// --- List all the auction transaction from the past 30 days
// let auction_transactions_last_30 = hetzner.get_auction_transactions();
// auction_transactions_last_30.pretty_print();
/// --- Fetch a auction transaction by ID
// let example_auction_transaction = hetzner.get_auction_transaction_by_id("");
// print(example_auction_transaction);
/// --- List all the auctioned server products
// let auctioned_servers = hetzner.get_auction_server_products();
// auctioned_servers.pretty_print();
/// --- Get information about one specific auctioned server by ID
let auctioned_server = hetzner.get_auction_server_product_by_id("2739567");
print(auctioned_server);
/// --- Order an auction server
// 1. Grab the SSH key to pass to the deployment
let ssh_key = hetzner.get_ssh_key("e0:73:80:26:80:46:f0:c8:bb:74:f4:d0:2d:10:2d:6f");
// 2. Order the auctioned server
let transaction = hetzner.order_auction_server(
auctioned_server.id,
[ssh_key], // Pass ssh_key as an array
(), // dist (Option<String>)
(), // arch (Option<String>)
(), // lang (Option<String>)
(), // comment (Option<String>)
[], // addons (Array)
(), // test (Option<bool>)
);
print(transaction);

View File

@ -8,9 +8,8 @@ keys.pretty_print();
// print(key);
// Add a new SSH key
// Replace "my-new-key" with the desired name and "ssh-rsa ..." with your public key data
// let new_key = hetzner.add_ssh_key("vanheesm@incubaid.com", "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFyZJCEsvRc0eitsOoq+ywC5Lmqejvk3hXMVbO0AxPrd");
// print(new_key);
let new_key = hetzner.add_ssh_key("vanheesm@incubaid.com", "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFyZJCEsvRc0eitsOoq+ywC5Lmqejvk3hXMVbO0AxPrd");
print(new_key);
// Update an SSH key's name
// Replace "cb:8b:ef:a7:fe:04:87:3f:e5:55:cd:12:e3:e8:9f:99" with the fingerprint of the key you want to update

View File

@ -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, OrderServerProduct, OrderServerProductWrapper, RescueWrapped, ServerWrapper, SshKeyWrapper, Transaction, TransactionWrapper
AuctionServerProduct, AuctionServerProductWrapper, AuctionTransaction, AuctionTransactionWrapper, BootWrapper, Cancellation, CancellationWrapper, OrderServerProduct, OrderServerProductWrapper, RescueWrapped, ServerWrapper, SshKeyWrapper, Transaction, TransactionWrapper
};
use crate::config::Config;
use error::AppError;
@ -246,7 +246,9 @@ impl Client {
Ok(wrapped.rescue)
}
pub fn get_server_ordering_product_overview(&self) -> Result<Vec<OrderServerProduct>, AppError> {
pub fn get_server_products(
&self,
) -> Result<Vec<OrderServerProduct>, AppError> {
let response = self
.http_client
.get(format!("{}/order/server/product", &self.config.api_url))
@ -258,10 +260,16 @@ impl Client {
Ok(products)
}
pub fn get_server_ordering_product_by_id(&self, product_id: &str) -> Result<OrderServerProduct, AppError> {
pub fn get_server_product_by_id(
&self,
product_id: &str,
) -> Result<OrderServerProduct, AppError> {
let response = self
.http_client
.get(format!("{}/order/server/product/{}", &self.config.api_url, product_id))
.get(format!(
"{}/order/server/product/{}",
&self.config.api_url, product_id
))
.basic_auth(&self.config.username, Some(&self.config.password))
.send()?;
@ -301,7 +309,10 @@ impl Client {
pub fn get_transaction_by_id(&self, transaction_id: &str) -> Result<Transaction, AppError> {
let response = self
.http_client
.get(format!("{}/order/server/transaction/{}", &self.config.api_url, transaction_id))
.get(format!(
"{}/order/server/transaction/{}",
&self.config.api_url, transaction_id
))
.basic_auth(&self.config.username, Some(&self.config.password))
.send()?;
@ -319,4 +330,95 @@ impl Client {
let transactions = wrapped.into_iter().map(|t| t.transaction).collect();
Ok(transactions)
}
pub fn get_auction_server_products(&self) -> Result<Vec<AuctionServerProduct>, AppError> {
let response = self
.http_client
.get(format!(
"{}/order/server_market/product",
&self.config.api_url
))
.basic_auth(&self.config.username, Some(&self.config.password))
.send()?;
let wrapped: Vec<AuctionServerProductWrapper> = self.handle_response(response)?;
let products = wrapped.into_iter().map(|asp| asp.product).collect();
Ok(products)
}
pub fn get_auction_server_product_by_id(&self, product_id: &str) -> Result<AuctionServerProduct, AppError> {
let response = self
.http_client
.get(format!("{}/order/server_market/product/{}", &self.config.api_url, product_id))
.basic_auth(&self.config.username, Some(&self.config.password))
.send()?;
let wrapped: AuctionServerProductWrapper = self.handle_response(response)?;
Ok(wrapped.product)
}
pub fn get_auction_transactions(&self) -> Result<Vec<AuctionTransaction>, AppError> {
let response = self
.http_client
.get(format!("{}/order/server_market/transaction", &self.config.api_url))
.basic_auth(&self.config.username, Some(&self.config.password))
.send()?;
let wrapped: Vec<AuctionTransactionWrapper> = self.handle_response(response)?;
let transactions = wrapped.into_iter().map(|t| t.transaction).collect();
Ok(transactions)
}
pub fn get_auction_transaction_by_id(&self, transaction_id: &str) -> Result<AuctionTransaction, AppError> {
let response = self
.http_client
.get(format!("{}/order/server_market/transaction/{}", &self.config.api_url, transaction_id))
.basic_auth(&self.config.username, Some(&self.config.password))
.send()?;
let wrapped: AuctionTransactionWrapper = self.handle_response(response)?;
Ok(wrapped.transaction)
}
pub fn order_auction_server(
&self,
product_id: i32,
authorized_keys: Vec<String>,
dist: Option<String>,
arch: Option<String>,
lang: Option<String>,
comment: Option<String>,
addons: Option<Vec<String>>,
test: Option<bool>,
) -> Result<AuctionTransaction, AppError> {
let mut params = json!({
"product_id": product_id,
"authorized_key": authorized_keys,
});
if let Some(dist) = dist {
params["dist"] = json!(dist);
}
if let Some(arch) = arch {
params["@deprecated arch"] = json!(arch);
}
if let Some(lang) = lang {
params["lang"] = json!(lang);
}
if let Some(comment) = comment {
params["comment"] = json!(comment);
}
if let Some(addons) = addons {
params["addon"] = json!(addons);
}
if let Some(test) = test {
params["test"] = json!(test);
}
let response = self
.http_client
.post(format!("{}/order/server_market/transaction", &self.config.api_url))
.basic_auth(&self.config.username, Some(&self.config.password))
.json(&params)
.send()?;
let wrapped: AuctionTransactionWrapper = self.handle_response(response)?;
Ok(wrapped.transaction)
}
}

View File

@ -999,4 +999,282 @@ impl HostKey {
.with_get("key_type", |k: &mut HostKey| k.key_type.clone())
.with_get("size", |k: &mut HostKey| k.size);
}
}
#[derive(Debug, Deserialize, Clone)]
pub struct AuctionServerProductWrapper {
pub product: AuctionServerProduct,
}
#[derive(Debug, Deserialize, Clone, CustomType)]
#[rhai_type(extra = Self::build_rhai_type)]
pub struct AuctionServerProduct {
pub id: i32,
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>,
pub cpu: String,
pub cpu_benchmark: i32,
pub memory_size: i32,
pub hdd_size: i32,
pub hdd_text: String,
pub hdd_count: i32,
pub datacenter: String,
pub network_speed: String,
pub price: String,
pub price_hourly: Option<String>,
pub price_setup: String,
#[serde(rename = "price_vat")]
pub price_with_vat: String,
#[serde(rename = "price_hourly_vat")]
pub price_hourly_with_vat: Option<String>,
#[serde(rename = "price_setup_vat")]
pub price_setup_with_vat: String,
pub fixed_price: bool,
pub next_reduce: i32,
pub next_reduce_date: String,
pub orderable_addons: Vec<OrderableAddon>,
}
impl AuctionServerProduct {
fn build_rhai_type(builder: &mut TypeBuilder<Self>) {
builder
.with_name("AuctionServerProduct")
.with_get("id", |p: &mut AuctionServerProduct| p.id)
.with_get("name", |p: &mut AuctionServerProduct| p.name.clone())
.with_get("description", |p: &mut AuctionServerProduct| p.description.clone())
.with_get("traffic", |p: &mut AuctionServerProduct| p.traffic.clone())
.with_get("dist", |p: &mut AuctionServerProduct| p.dist.clone())
.with_get("arch", |p: &mut AuctionServerProduct| p.arch.clone())
.with_get("lang", |p: &mut AuctionServerProduct| p.lang.clone())
.with_get("cpu", |p: &mut AuctionServerProduct| p.cpu.clone())
.with_get("cpu_benchmark", |p: &mut AuctionServerProduct| p.cpu_benchmark)
.with_get("memory_size", |p: &mut AuctionServerProduct| p.memory_size)
.with_get("hdd_size", |p: &mut AuctionServerProduct| p.hdd_size)
.with_get("hdd_text", |p: &mut AuctionServerProduct| p.hdd_text.clone())
.with_get("hdd_count", |p: &mut AuctionServerProduct| p.hdd_count)
.with_get("datacenter", |p: &mut AuctionServerProduct| p.datacenter.clone())
.with_get("network_speed", |p: &mut AuctionServerProduct| p.network_speed.clone())
.with_get("price", |p: &mut AuctionServerProduct| p.price.clone())
.with_get("price_hourly", |p: &mut AuctionServerProduct| p.price_hourly.clone())
.with_get("price_setup", |p: &mut AuctionServerProduct| p.price_setup.clone())
.with_get("price_with_vat", |p: &mut AuctionServerProduct| p.price_with_vat.clone())
.with_get("price_hourly_with_vat", |p: &mut AuctionServerProduct| p.price_hourly_with_vat.clone())
.with_get("price_setup_with_vat", |p: &mut AuctionServerProduct| p.price_setup_with_vat.clone())
.with_get("fixed_price", |p: &mut AuctionServerProduct| p.fixed_price)
.with_get("next_reduce", |p: &mut AuctionServerProduct| p.next_reduce)
.with_get("next_reduce_date", |p: &mut AuctionServerProduct| p.next_reduce_date.clone())
.with_get("orderable_addons", |p: &mut AuctionServerProduct| p.orderable_addons.clone())
.on_print(|p: &mut AuctionServerProduct| p.to_string())
.with_fn("pretty_print", |p: &mut AuctionServerProduct| p.to_string());
}
}
impl fmt::Display for AuctionServerProduct {
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.to_string()]);
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!["CPU", self.cpu.clone()]);
table.add_row(row!["CPU Benchmark", self.cpu_benchmark.to_string()]);
table.add_row(row!["Memory Size (GB)", self.memory_size.to_string()]);
table.add_row(row!["HDD Size (GB)", self.hdd_size.to_string()]);
table.add_row(row!["HDD Text", self.hdd_text.clone()]);
table.add_row(row!["HDD Count", self.hdd_count.to_string()]);
table.add_row(row!["Datacenter", self.datacenter.clone()]);
table.add_row(row!["Network Speed", self.network_speed.clone()]);
table.add_row(row!["Price (Net)", self.price.clone()]);
table.add_row(row!["Price (Hourly Net)", self.price_hourly.as_deref().unwrap_or("N/A").to_string()]);
table.add_row(row!["Price (Setup Net)", self.price_setup.clone()]);
table.add_row(row!["Price (VAT)", self.price_with_vat.clone()]);
table.add_row(row!["Price (Hourly VAT)", self.price_hourly_with_vat.as_deref().unwrap_or("N/A").to_string()]);
table.add_row(row!["Price (Setup VAT)", self.price_setup_with_vat.clone()]);
table.add_row(row!["Fixed Price", self.fixed_price.to_string()]);
table.add_row(row!["Next Reduce (seconds)", self.next_reduce.to_string()]);
table.add_row(row!["Next Reduce Date", self.next_reduce_date.clone()]);
let mut addons_table = Table::new();
addons_table.add_row(row![b => "ID", "Name", "Min", "Max", "Prices"]);
for addon in &self.orderable_addons {
let mut addon_prices_table = Table::new();
addon_prices_table.add_row(row![b => "Location", "Net", "Gross", "Hourly Net", "Hourly Gross", "Setup Net", "Setup Gross"]);
for price in &addon.prices {
addon_prices_table.add_row(row![
price.location,
price.price.net,
price.price.gross,
price.price.hourly_net,
price.price.hourly_gross,
price.price_setup.net,
price.price_setup.gross
]);
}
addons_table.add_row(row![
addon.id,
addon.name,
addon.min,
addon.max,
addon_prices_table
]);
}
table.add_row(row!["Orderable Addons", addons_table]);
write!(f, "{}", table)
}
}
#[derive(Debug, Deserialize, Clone)]
pub struct AuctionTransactionWrapper {
pub transaction: AuctionTransaction,
}
#[derive(Debug, Deserialize, Clone, CustomType)]
#[rhai_type(extra = Self::build_rhai_type)]
pub struct AuctionTransaction {
pub id: String,
pub date: String,
pub status: String,
pub server_number: Option<i32>,
pub server_ip: Option<String>,
pub authorized_key: Vec<AuthorizedKeyWrapper>,
pub host_key: Vec<HostKeyWrapper>,
pub comment: Option<String>,
pub product: AuctionTransactionProduct,
pub addons: Vec<String>,
}
#[derive(Debug, Deserialize, Clone, CustomType)]
#[rhai_type(extra = Self::build_rhai_type)]
pub struct AuctionTransactionProduct {
pub id: i32,
pub name: String,
pub description: Vec<String>,
pub traffic: String,
pub dist: String,
#[serde(rename = "@deprecated arch")]
pub arch: String,
pub lang: String,
pub cpu: String,
pub cpu_benchmark: i32,
pub memory_size: i32,
pub hdd_size: i32,
pub hdd_text: String,
pub hdd_count: i32,
pub datacenter: String,
pub network_speed: String,
pub fixed_price: bool,
pub next_reduce: i32,
pub next_reduce_date: String,
}
impl AuctionTransaction {
fn build_rhai_type(builder: &mut TypeBuilder<Self>) {
builder
.with_name("AuctionTransaction")
.with_get("id", |t: &mut AuctionTransaction| t.id.clone())
.with_get("date", |t: &mut AuctionTransaction| t.date.clone())
.with_get("status", |t: &mut AuctionTransaction| t.status.clone())
.with_get("server_number", |t: &mut AuctionTransaction| t.server_number)
.with_get("server_ip", |t: &mut AuctionTransaction| t.server_ip.clone())
.with_get("authorized_key", |t: &mut AuctionTransaction| t.authorized_key.clone())
.with_get("host_key", |t: &mut AuctionTransaction| t.host_key.clone())
.with_get("comment", |t: &mut AuctionTransaction| t.comment.clone())
.with_get("product", |t: &mut AuctionTransaction| t.product.clone())
.with_get("addons", |t: &mut AuctionTransaction| t.addons.clone());
}
}
impl AuctionTransactionProduct {
fn build_rhai_type(builder: &mut TypeBuilder<Self>) {
builder
.with_name("AuctionTransactionProduct")
.with_get("id", |p: &mut AuctionTransactionProduct| p.id)
.with_get("name", |p: &mut AuctionTransactionProduct| p.name.clone())
.with_get("description", |p: &mut AuctionTransactionProduct| p.description.clone())
.with_get("traffic", |p: &mut AuctionTransactionProduct| p.traffic.clone())
.with_get("dist", |p: &mut AuctionTransactionProduct| p.dist.clone())
.with_get("arch", |p: &mut AuctionTransactionProduct| p.arch.clone())
.with_get("lang", |p: &mut AuctionTransactionProduct| p.lang.clone())
.with_get("cpu", |p: &mut AuctionTransactionProduct| p.cpu.clone())
.with_get("cpu_benchmark", |p: &mut AuctionTransactionProduct| p.cpu_benchmark)
.with_get("memory_size", |p: &mut AuctionTransactionProduct| p.memory_size)
.with_get("hdd_size", |p: &mut AuctionTransactionProduct| p.hdd_size)
.with_get("hdd_text", |p: &mut AuctionTransactionProduct| p.hdd_text.clone())
.with_get("hdd_count", |p: &mut AuctionTransactionProduct| p.hdd_count)
.with_get("datacenter", |p: &mut AuctionTransactionProduct| p.datacenter.clone())
.with_get("network_speed", |p: &mut AuctionTransactionProduct| p.network_speed.clone())
.with_get("fixed_price", |p: &mut AuctionTransactionProduct| p.fixed_price)
.with_get("next_reduce", |p: &mut AuctionTransactionProduct| p.next_reduce)
.with_get("next_reduce_date", |p: &mut AuctionTransactionProduct| p.next_reduce_date.clone());
}
}
impl fmt::Display for AuctionTransaction {
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!["Date", self.date.clone()]);
table.add_row(row!["Status", self.status.clone()]);
table.add_row(row!["Server Number", self.server_number.map_or("N/A".to_string(), |id| id.to_string())]);
table.add_row(row!["Server IP", self.server_ip.as_deref().unwrap_or("N/A").to_string()]);
table.add_row(row!["Comment", self.comment.as_deref().unwrap_or("N/A").to_string()]);
table.add_row(row!["Product ID", self.product.id.to_string()]);
table.add_row(row!["Product Name", self.product.name.clone()]);
table.add_row(row!["Product Description", self.product.description.join(", ")]);
table.add_row(row!["Product Traffic", self.product.traffic.clone()]);
table.add_row(row!["Product Distributions", self.product.dist.clone()]);
table.add_row(row!["Product Architectures", self.product.arch.clone()]);
table.add_row(row!["Product Languages", self.product.lang.clone()]);
table.add_row(row!["Product CPU", self.product.cpu.clone()]);
table.add_row(row!["Product CPU Benchmark", self.product.cpu_benchmark.to_string()]);
table.add_row(row!["Product Memory Size (GB)", self.product.memory_size.to_string()]);
table.add_row(row!["Product HDD Size (GB)", self.product.hdd_size.to_string()]);
table.add_row(row!["Product HDD Text", self.product.hdd_text.clone()]);
table.add_row(row!["Product HDD Count", self.product.hdd_count.to_string()]);
table.add_row(row!["Product Datacenter", self.product.datacenter.clone()]);
table.add_row(row!["Product Network Speed", self.product.network_speed.clone()]);
table.add_row(row!["Product Fixed Price", self.product.fixed_price.to_string()]);
table.add_row(row!["Product Next Reduce (seconds)", self.product.next_reduce.to_string()]);
table.add_row(row!["Product Next Reduce Date", self.product.next_reduce_date.clone()]);
table.add_row(row!["Addons", self.addons.join(", ")]);
let mut authorized_keys_table = Table::new();
authorized_keys_table.add_row(row![b => "Name", "Fingerprint", "Type", "Size"]);
for key in &self.authorized_key {
authorized_keys_table.add_row(row![
key.key.name,
key.key.fingerprint,
key.key.key_type,
key.key.size
]);
}
table.add_row(row!["Authorized Keys", authorized_keys_table]);
let mut host_keys_table = Table::new();
host_keys_table.add_row(row![b => "Fingerprint", "Type", "Size"]);
for key in &self.host_key {
host_keys_table.add_row(row![
key.key.fingerprint,
key.key.key_type,
key.key.size
]);
}
table.add_row(row!["Host Keys", host_keys_table]);
write!(f, "{}", table)
}
}

View File

@ -1,12 +1,16 @@
use crate::api::Client;
use crate::api::models::{Rescue, Linux, Vnc, Windows, Plesk, Cpanel, Boot, Server, SshKey, Cancellation, OrderServerProduct, Transaction, AuthorizedKey, TransactionProduct, HostKey};
use crate::api::models::{
AuctionServerProduct, AuctionTransaction, AuctionTransactionProduct, AuthorizedKey, Boot,
Cancellation, Cpanel, HostKey, Linux, OrderServerProduct, Plesk, Rescue, Server, SshKey,
Transaction, TransactionProduct, Vnc, Windows,
};
use rhai::{Engine, Scope};
pub mod server;
pub mod ssh_keys;
pub mod boot;
pub mod printing;
pub mod server;
pub mod server_ordering;
pub mod ssh_keys;
pub fn setup_engine(client: Client) -> (Engine, Scope<'static>) {
let mut engine = Engine::new();
@ -27,6 +31,9 @@ pub fn setup_engine(client: Client) -> (Engine, Scope<'static>) {
engine.build_type::<AuthorizedKey>();
engine.build_type::<TransactionProduct>();
engine.build_type::<HostKey>();
engine.build_type::<AuctionServerProduct>();
engine.build_type::<AuctionTransaction>();
engine.build_type::<AuctionTransactionProduct>();
server::register(&mut engine);
ssh_keys::register(&mut engine);
@ -37,4 +44,4 @@ pub fn setup_engine(client: Client) -> (Engine, Scope<'static>) {
scope.push("hetzner", client);
(engine, scope)
}
}

View File

@ -1,5 +1,5 @@
use rhai::{Array, Engine};
use crate::{api::models::OrderServerProduct, scripting::{Server, SshKey}};
use crate::{api::models::{OrderServerProduct, AuctionServerProduct, AuctionTransaction}, scripting::{Server, SshKey}};
mod servers_table;
mod ssh_keys_table;
@ -22,6 +22,10 @@ pub fn pretty_print_dispatch(array: Array) {
}
else if first.is::<OrderServerProduct>() {
server_ordering_table::pretty_print_server_products(array);
} else if first.is::<AuctionServerProduct>() {
server_ordering_table::pretty_print_auction_server_products(array);
} else if first.is::<AuctionTransaction>() {
server_ordering_table::pretty_print_auction_transactions(array);
} else {
// Generic fallback for other types
for item in array {

View File

@ -35,4 +35,182 @@ pub fn pretty_print_server_products(products: rhai::Array) {
}
}
table.printstd();
}
pub fn pretty_print_auction_server_products(products: rhai::Array) {
let mut table = Table::new();
table.add_row(row![b =>
"ID",
"Name",
"Description",
"Traffic",
"Distributions",
"Architectures",
"Languages",
"CPU",
"CPU Benchmark",
"Memory Size (GB)",
"HDD Size (GB)",
"HDD Text",
"HDD Count",
"Datacenter",
"Network Speed",
"Price (Net)",
"Price (Hourly Net)",
"Price (Setup Net)",
"Price (VAT)",
"Price (Hourly VAT)",
"Price (Setup VAT)",
"Fixed Price",
"Next Reduce (seconds)",
"Next Reduce Date",
"Orderable Addons",
]);
for product_dyn in products {
if let Some(product) = product_dyn.try_cast::<crate::api::models::AuctionServerProduct>() {
let mut addons_table = Table::new();
addons_table.add_row(row![b => "ID", "Name", "Min", "Max", "Prices"]);
for addon in &product.orderable_addons {
let mut addon_prices_table = Table::new();
addon_prices_table.add_row(row![b => "Location", "Net", "Gross", "Hourly Net", "Hourly Gross", "Setup Net", "Setup Gross"]);
for price in &addon.prices {
addon_prices_table.add_row(row![
price.location,
price.price.net,
price.price.gross,
price.price.hourly_net,
price.price.hourly_gross,
price.price_setup.net,
price.price_setup.gross
]);
}
addons_table.add_row(row![
addon.id,
addon.name,
addon.min,
addon.max,
addon_prices_table
]);
}
table.add_row(row![
product.id,
product.name,
product.description.join(", "),
product.traffic,
product.dist.join(", "),
product.arch.as_deref().unwrap_or_default().join(", "),
product.lang.join(", "),
product.cpu,
product.cpu_benchmark,
product.memory_size,
product.hdd_size,
product.hdd_text,
product.hdd_count,
product.datacenter,
product.network_speed,
product.price,
product.price_hourly.as_deref().unwrap_or("N/A"),
product.price_setup,
product.price_with_vat,
product.price_hourly_with_vat.as_deref().unwrap_or("N/A"),
product.price_setup_with_vat,
product.fixed_price,
product.next_reduce,
product.next_reduce_date,
addons_table,
]);
}
}
table.printstd();
}
pub fn pretty_print_auction_transactions(transactions: rhai::Array) {
let mut table = Table::new();
table.add_row(row![b =>
"ID",
"Date",
"Status",
"Server Number",
"Server IP",
"Comment",
"Product ID",
"Product Name",
"Product Traffic",
"Product Distributions",
"Product Architectures",
"Product Languages",
"Product CPU",
"Product CPU Benchmark",
"Product Memory Size (GB)",
"Product HDD Size (GB)",
"Product HDD Text",
"Product HDD Count",
"Product Datacenter",
"Product Network Speed",
"Product Fixed Price",
"Product Next Reduce (seconds)",
"Product Next Reduce Date",
"Addons",
]);
for transaction_dyn in transactions {
if let Some(transaction) = transaction_dyn.try_cast::<crate::api::models::AuctionTransaction>() {
let authorized_keys_table = {
let mut table = Table::new();
table.add_row(row![b => "Name", "Fingerprint", "Type", "Size"]);
for key in &transaction.authorized_key {
table.add_row(row![
key.key.name,
key.key.fingerprint,
key.key.key_type,
key.key.size
]);
}
table
};
let host_keys_table = {
let mut table = Table::new();
table.add_row(row![b => "Fingerprint", "Type", "Size"]);
for key in &transaction.host_key {
table.add_row(row![
key.key.fingerprint,
key.key.key_type,
key.key.size
]);
}
table
};
table.add_row(row![
transaction.id,
transaction.date,
transaction.status,
transaction.server_number.map_or("N/A".to_string(), |id| id.to_string()),
transaction.server_ip.as_deref().unwrap_or("N/A"),
transaction.comment.as_deref().unwrap_or("N/A"),
transaction.product.id,
transaction.product.name,
transaction.product.traffic,
transaction.product.dist,
transaction.product.arch,
transaction.product.lang,
transaction.product.cpu,
transaction.product.cpu_benchmark,
transaction.product.memory_size,
transaction.product.hdd_size,
transaction.product.hdd_text,
transaction.product.hdd_count,
transaction.product.datacenter,
transaction.product.network_speed,
transaction.product.fixed_price,
transaction.product.next_reduce,
transaction.product.next_reduce_date,
transaction.addons.join(", "),
]);
}
}
table.printstd();
}

View File

@ -1,4 +1,7 @@
use crate::api::{Client, models::{OrderServerProduct, Transaction, SshKey}};
use crate::api::{
Client,
models::{AuctionServerProduct, AuctionTransaction, OrderServerProduct, SshKey, Transaction},
};
use rhai::{Array, Dynamic, plugin::*};
pub fn register(engine: &mut Engine) {
@ -9,23 +12,23 @@ pub fn register(engine: &mut Engine) {
#[export_module]
pub mod server_order_api {
#[rhai_fn(name = "get_server_ordering_product_overview", return_raw)]
#[rhai_fn(name = "get_server_products", 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()
.get_server_products()
.map_err(|e| Into::<Box<EvalAltResult>>::into(e.to_string()))?;
Ok(overview_servers.into_iter().map(Dynamic::from).collect())
}
#[rhai_fn(name = "get_server_ordering_product_by_id", return_raw)]
#[rhai_fn(name = "get_server_product_by_id", return_raw)]
pub fn get_server_ordering_product_by_id(
client: &mut Client,
product_id: &str,
) -> Result<OrderServerProduct, Box<EvalAltResult>> {
let product = client
.get_server_ordering_product_by_id(product_id)
.get_server_product_by_id(product_id)
.map_err(|e| Into::<Box<EvalAltResult>>::into(e.to_string()))?;
Ok(product)
}
@ -56,9 +59,14 @@ pub mod server_order_api {
let addons = if addons.is_empty() {
None
} else {
Some(addons.into_iter().map(|a| a.into_string().unwrap()).collect())
Some(
addons
.into_iter()
.map(|a| a.into_string().unwrap())
.collect(),
)
};
let transaction = client
.order_server(product_id, dist, location, authorized_keys, addons)
.map_err(|e| Into::<Box<EvalAltResult>>::into(e.to_string()))?;
@ -83,4 +91,94 @@ pub mod server_order_api {
.map_err(|e| Into::<Box<EvalAltResult>>::into(e.to_string()))?;
Ok(transactions.into_iter().map(Dynamic::from).collect())
}
#[rhai_fn(name = "get_auction_server_products", return_raw)]
pub fn get_auction_server_products(client: &mut Client) -> Result<Array, Box<EvalAltResult>> {
let products = client
.get_auction_server_products()
.map_err(|e| Into::<Box<EvalAltResult>>::into(e.to_string()))?;
Ok(products.into_iter().map(Dynamic::from).collect())
}
#[rhai_fn(name = "get_auction_server_product_by_id", return_raw)]
pub fn get_auction_server_product_by_id(
client: &mut Client,
product_id: &str,
) -> Result<AuctionServerProduct, Box<EvalAltResult>> {
let product = client
.get_auction_server_product_by_id(product_id)
.map_err(|e| Into::<Box<EvalAltResult>>::into(e.to_string()))?;
Ok(product)
}
#[rhai_fn(name = "get_auction_transactions", return_raw)]
pub fn get_auction_transactions(client: &mut Client) -> Result<Array, Box<EvalAltResult>> {
let transactions = client
.get_auction_transactions()
.map_err(|e| Into::<Box<EvalAltResult>>::into(e.to_string()))?;
Ok(transactions.into_iter().map(Dynamic::from).collect())
}
#[rhai_fn(name = "get_auction_transaction_by_id", return_raw)]
pub fn get_auction_transaction_by_id(
client: &mut Client,
transaction_id: &str,
) -> Result<AuctionTransaction, Box<EvalAltResult>> {
let transaction = client
.get_auction_transaction_by_id(transaction_id)
.map_err(|e| Into::<Box<EvalAltResult>>::into(e.to_string()))?;
Ok(transaction)
}
#[rhai_fn(name = "order_auction_server", return_raw)]
pub fn order_auction_server(
client: &mut Client,
product_id: i32,
authorized_keys: Array,
dist: Option<String>,
arch: Option<String>,
lang: Option<String>,
comment: Option<String>,
addons: Array,
test: Option<bool>,
) -> Result<AuctionTransaction, Box<EvalAltResult>> {
let authorized_keys: Vec<String> = if authorized_keys.is_empty() {
vec![]
} else if authorized_keys[0].is::<SshKey>() {
authorized_keys
.into_iter()
.map(|k| k.cast::<SshKey>().fingerprint)
.collect()
} else {
authorized_keys
.into_iter()
.map(|k| k.into_string().unwrap())
.collect()
};
let addons = if addons.is_empty() {
None
} else {
Some(
addons
.into_iter()
.map(|a| a.into_string().unwrap())
.collect(),
)
};
let transaction = client
.order_auction_server(
product_id,
authorized_keys,
dist,
arch,
lang,
comment,
addons,
test,
)
.map_err(|e| Into::<Box<EvalAltResult>>::into(e.to_string()))?;
Ok(transaction)
}
}