added all requirements to order auction server + tested it

This commit is contained in:
Maxime Van Hees 2025-07-23 15:33:33 +02:00
parent a92b896d17
commit 721f918270
7 changed files with 312 additions and 177 deletions

View File

@ -27,22 +27,23 @@
// auctioned_servers.pretty_print(); // auctioned_servers.pretty_print();
/// --- Get information about one specific auctioned server by ID /// --- Get information about one specific auctioned server by ID
let auctioned_server = hetzner.get_auction_server_product_by_id("2739567"); // let auctioned_server = hetzner.get_auction_server_product_by_id("2739642");
print(auctioned_server); // print(auctioned_server);
/// --- Order an auction server /// --- Order an auction server
// 1. Grab the SSH key to pass to the deployment // 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"); 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 // 2. Use the builder to bundle the details on what to order
let transaction = hetzner.order_auction_server( // let order_builder = new_auction_server_builder(2741558)
auctioned_server.id, // .with_authorized_keys([ssh_key.fingerprint])
[ssh_key], // Pass ssh_key as an array // .with_lang("en")
(), // dist (Option<String>) // .with_comment("test")
(), // arch (Option<String>) // .with_test(false);
(), // lang (Option<String>)
(), // comment (Option<String>)
[], // addons (Array)
(), // test (Option<bool>)
);
print(transaction);
// let ordered_auction_server = hetzner.order_auction_server(order_builder);
// print(ordered_auction_server);
// --> we get a transaction ID from this --> which we can use to fetch information about the transaction
// e.g. B20250723-3204053-2775263
let transaction = hetzner.get_auction_transaction_by_id("B20250723-3204053-2775263");
print(transaction)

View File

@ -378,7 +378,7 @@ impl Client {
} }
pub fn order_auction_server( pub fn order_auction_server(
&self, &self,
product_id: i32, product_id: i64,
authorized_keys: Vec<String>, authorized_keys: Vec<String>,
dist: Option<String>, dist: Option<String>,
arch: Option<String>, arch: Option<String>,
@ -387,35 +387,40 @@ impl Client {
addons: Option<Vec<String>>, addons: Option<Vec<String>>,
test: Option<bool>, test: Option<bool>,
) -> Result<AuctionTransaction, AppError> { ) -> Result<AuctionTransaction, AppError> {
let mut params = json!({ let mut params: Vec<(&str, String)> = Vec::new();
"product_id": product_id,
"authorized_key": authorized_keys, params.push(("product_id", product_id.to_string()));
});
for key in &authorized_keys {
params.push(("authorized_key[]", key.clone()));
}
if let Some(dist) = dist { if let Some(dist) = dist {
params["dist"] = json!(dist); params.push(("dist", dist));
} }
if let Some(arch) = arch { if let Some(arch) = arch {
params["@deprecated arch"] = json!(arch); params.push(("@deprecated arch", arch));
} }
if let Some(lang) = lang { if let Some(lang) = lang {
params["lang"] = json!(lang); params.push(("lang", lang));
} }
if let Some(comment) = comment { if let Some(comment) = comment {
params["comment"] = json!(comment); params.push(("comment", comment));
} }
if let Some(addons) = addons { if let Some(addons) = addons {
params["addon"] = json!(addons); for addon in addons {
params.push(("addon[]", addon));
}
} }
if let Some(test) = test { if let Some(test) = test {
params["test"] = json!(test); params.push(("test", test.to_string()));
} }
let response = self let response = self
.http_client .http_client
.post(format!("{}/order/server_market/transaction", &self.config.api_url)) .post(format!("{}/order/server_market/transaction", &self.config.api_url))
.basic_auth(&self.config.username, Some(&self.config.password)) .basic_auth(&self.config.username, Some(&self.config.password))
.json(&params) .form(&params)
.send()?; .send()?;
let wrapped: AuctionTransactionWrapper = self.handle_response(response)?; let wrapped: AuctionTransactionWrapper = self.handle_response(response)?;

View File

@ -1,8 +1,8 @@
use rhai::{CustomType, TypeBuilder}; use prettytable::{Table, row};
use rhai::{Array, CustomType, TypeBuilder};
use serde::{Deserialize, Deserializer}; use serde::{Deserialize, Deserializer};
use serde_json::Value; use serde_json::Value;
use std::fmt; use std::fmt;
use prettytable::{row, Table};
#[derive(Debug, Deserialize, Clone)] #[derive(Debug, Deserialize, Clone)]
pub struct ServerWrapper { pub struct ServerWrapper {
@ -40,7 +40,9 @@ impl Server {
builder builder
.with_name("Server") .with_name("Server")
.with_get("server_ip", |s: &mut Server| s.server_ip.clone()) .with_get("server_ip", |s: &mut Server| s.server_ip.clone())
.with_get("server_ipv6_net", |s: &mut Server| s.server_ipv6_net.clone()) .with_get("server_ipv6_net", |s: &mut Server| {
s.server_ipv6_net.clone()
})
.with_get("server_number", |s: &mut Server| s.server_number) .with_get("server_number", |s: &mut Server| s.server_number)
.with_get("server_name", |s: &mut Server| s.server_name.clone()) .with_get("server_name", |s: &mut Server| s.server_name.clone())
.with_get("product", |s: &mut Server| s.product.clone()) .with_get("product", |s: &mut Server| s.product.clone())
@ -152,13 +154,7 @@ impl SshKey {
impl fmt::Display for SshKey { impl fmt::Display for SshKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut table = Table::new(); let mut table = Table::new();
table.add_row(row![ table.add_row(row!["Name", "Fingerprint", "Type", "Size", "Created At"]);
"Name",
"Fingerprint",
"Type",
"Size",
"Created At"
]);
table.add_row(row![ table.add_row(row![
self.name.clone(), self.name.clone(),
self.fingerprint.clone(), self.fingerprint.clone(),
@ -251,9 +247,7 @@ impl Rescue {
.with_get("os", |r: &mut Rescue| r.os.clone()) .with_get("os", |r: &mut Rescue| r.os.clone())
.with_get("active", |r: &mut Rescue| r.active) .with_get("active", |r: &mut Rescue| r.active)
.with_get("password", |r: &mut Rescue| r.password.clone()) .with_get("password", |r: &mut Rescue| r.password.clone())
.with_get("authorized_key", |r: &mut Rescue| { .with_get("authorized_key", |r: &mut Rescue| r.authorized_key.clone())
r.authorized_key.clone()
})
.with_get("host_key", |r: &mut Rescue| r.host_key.clone()) .with_get("host_key", |r: &mut Rescue| r.host_key.clone())
.on_print(|r: &mut Rescue| r.to_string()) .on_print(|r: &mut Rescue| r.to_string())
.with_fn("pretty_print", |r: &mut Rescue| r.to_string()); .with_fn("pretty_print", |r: &mut Rescue| r.to_string());
@ -293,17 +287,13 @@ impl Linux {
builder builder
.with_name("Linux") .with_name("Linux")
.with_get("server_ip", |l: &mut Linux| l.server_ip.clone()) .with_get("server_ip", |l: &mut Linux| l.server_ip.clone())
.with_get("server_ipv6_net", |l: &mut Linux| { .with_get("server_ipv6_net", |l: &mut Linux| l.server_ipv6_net.clone())
l.server_ipv6_net.clone()
})
.with_get("server_number", |l: &mut Linux| l.server_number) .with_get("server_number", |l: &mut Linux| l.server_number)
.with_get("dist", |l: &mut Linux| l.dist.clone()) .with_get("dist", |l: &mut Linux| l.dist.clone())
.with_get("lang", |l: &mut Linux| l.lang.clone()) .with_get("lang", |l: &mut Linux| l.lang.clone())
.with_get("active", |l: &mut Linux| l.active) .with_get("active", |l: &mut Linux| l.active)
.with_get("password", |l: &mut Linux| l.password.clone()) .with_get("password", |l: &mut Linux| l.password.clone())
.with_get("authorized_key", |l: &mut Linux| { .with_get("authorized_key", |l: &mut Linux| l.authorized_key.clone())
l.authorized_key.clone()
})
.with_get("host_key", |l: &mut Linux| l.host_key.clone()) .with_get("host_key", |l: &mut Linux| l.host_key.clone())
.on_print(|l: &mut Linux| l.to_string()) .on_print(|l: &mut Linux| l.to_string())
.with_fn("pretty_print", |l: &mut Linux| l.to_string()); .with_fn("pretty_print", |l: &mut Linux| l.to_string());
@ -428,9 +418,7 @@ impl Plesk {
builder builder
.with_name("Plesk") .with_name("Plesk")
.with_get("server_ip", |p: &mut Plesk| p.server_ip.clone()) .with_get("server_ip", |p: &mut Plesk| p.server_ip.clone())
.with_get("server_ipv6_net", |p: &mut Plesk| { .with_get("server_ipv6_net", |p: &mut Plesk| p.server_ipv6_net.clone())
p.server_ipv6_net.clone()
})
.with_get("server_number", |p: &mut Plesk| p.server_number) .with_get("server_number", |p: &mut Plesk| p.server_number)
.with_get("dist", |p: &mut Plesk| p.dist.clone()) .with_get("dist", |p: &mut Plesk| p.dist.clone())
.with_get("lang", |p: &mut Plesk| p.lang.clone()) .with_get("lang", |p: &mut Plesk| p.lang.clone())
@ -558,10 +546,7 @@ impl fmt::Display for Cancellation {
table.add_row(row!["Server IP", self.server_ip.clone()]); table.add_row(row!["Server IP", self.server_ip.clone()]);
table.add_row(row![ table.add_row(row![
"Server IPv6 Net", "Server IPv6 Net",
self.server_ipv6_net self.server_ipv6_net.as_deref().unwrap_or("N/A").to_string()
.as_deref()
.unwrap_or("N/A")
.to_string()
]); ]);
table.add_row(row!["Server Number", self.server_number.to_string()]); table.add_row(row!["Server Number", self.server_number.to_string()]);
table.add_row(row!["Server Name", self.server_name.clone()]); table.add_row(row!["Server Name", self.server_name.clone()]);
@ -570,7 +555,10 @@ impl fmt::Display for Cancellation {
self.earliest_cancellation_date.clone() self.earliest_cancellation_date.clone()
]); ]);
table.add_row(row!["Cancelled", self.cancelled.to_string()]); table.add_row(row!["Cancelled", self.cancelled.to_string()]);
table.add_row(row!["Reservation Possible", self.reservation_possible.to_string()]); table.add_row(row![
"Reservation Possible",
self.reservation_possible.to_string()
]);
table.add_row(row!["Reserved", self.reserved.to_string()]); table.add_row(row!["Reserved", self.reserved.to_string()]);
table.add_row(row![ table.add_row(row![
"Cancellation Date", "Cancellation Date",
@ -608,9 +596,7 @@ where
} }
} }
fn option_string_or_seq_string<'de, D>( fn option_string_or_seq_string<'de, D>(deserializer: D) -> Result<Option<Vec<String>>, D::Error>
deserializer: D,
) -> Result<Option<Vec<String>>, D::Error>
where where
D: Deserializer<'de>, D: Deserializer<'de>,
{ {
@ -645,7 +631,9 @@ impl From<reqwest::blocking::Response> for ApiError {
fn from(value: reqwest::blocking::Response) -> Self { fn from(value: reqwest::blocking::Response) -> Self {
ApiError { ApiError {
status: value.status().into(), status: value.status().into(),
message: value.text().unwrap_or("The API call returned an error.".to_string()), message: value
.text()
.unwrap_or("The API call returned an error.".to_string()),
} }
} }
} }
@ -788,7 +776,11 @@ pub struct OrderServerProduct {
pub traffic: String, pub traffic: String,
#[serde(deserialize_with = "string_or_seq_string")] #[serde(deserialize_with = "string_or_seq_string")]
pub dist: Vec<String>, pub dist: Vec<String>,
#[serde(rename = "@deprecated arch", default, deserialize_with = "option_string_or_seq_string")] #[serde(
rename = "@deprecated arch",
default,
deserialize_with = "option_string_or_seq_string"
)]
#[deprecated(note = "use `dist` instead")] #[deprecated(note = "use `dist` instead")]
pub arch: Option<Vec<String>>, pub arch: Option<Vec<String>>,
#[serde(deserialize_with = "string_or_seq_string")] #[serde(deserialize_with = "string_or_seq_string")]
@ -805,14 +797,18 @@ impl OrderServerProduct {
.with_name("OrderServerProduct") .with_name("OrderServerProduct")
.with_get("id", |o: &mut OrderServerProduct| o.id.clone()) .with_get("id", |o: &mut OrderServerProduct| o.id.clone())
.with_get("name", |o: &mut OrderServerProduct| o.name.clone()) .with_get("name", |o: &mut OrderServerProduct| o.name.clone())
.with_get("description", |o: &mut OrderServerProduct| o.description.clone()) .with_get("description", |o: &mut OrderServerProduct| {
o.description.clone()
})
.with_get("traffic", |o: &mut OrderServerProduct| o.traffic.clone()) .with_get("traffic", |o: &mut OrderServerProduct| o.traffic.clone())
.with_get("dist", |o: &mut OrderServerProduct| o.dist.clone()) .with_get("dist", |o: &mut OrderServerProduct| o.dist.clone())
.with_get("arch", |o: &mut OrderServerProduct| o.arch.clone()) .with_get("arch", |o: &mut OrderServerProduct| o.arch.clone())
.with_get("lang", |o: &mut OrderServerProduct| o.lang.clone()) .with_get("lang", |o: &mut OrderServerProduct| o.lang.clone())
.with_get("location", |o: &mut OrderServerProduct| o.location.clone()) .with_get("location", |o: &mut OrderServerProduct| o.location.clone())
.with_get("prices", |o: &mut OrderServerProduct| o.prices.clone()) .with_get("prices", |o: &mut OrderServerProduct| o.prices.clone())
.with_get("orderable_addons", |o: &mut OrderServerProduct| o.orderable_addons.clone()) .with_get("orderable_addons", |o: &mut OrderServerProduct| {
o.orderable_addons.clone()
})
.on_print(|o: &mut OrderServerProduct| o.to_string()) .on_print(|o: &mut OrderServerProduct| o.to_string())
.with_fn("pretty_print", |o: &mut OrderServerProduct| o.to_string()); .with_fn("pretty_print", |o: &mut OrderServerProduct| o.to_string());
} }
@ -827,7 +823,10 @@ impl fmt::Display for OrderServerProduct {
table.add_row(row!["Description", self.description.join(", ")]); table.add_row(row!["Description", self.description.join(", ")]);
table.add_row(row!["Traffic", self.traffic.clone()]); table.add_row(row!["Traffic", self.traffic.clone()]);
table.add_row(row!["Distributions", self.dist.join(", ")]); 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![
"Architectures",
self.arch.as_deref().unwrap_or_default().join(", ")
]);
table.add_row(row!["Languages", self.lang.join(", ")]); table.add_row(row!["Languages", self.lang.join(", ")]);
table.add_row(row!["Locations", self.location.join(", ")]); table.add_row(row!["Locations", self.location.join(", ")]);
let mut prices_table = Table::new(); let mut prices_table = Table::new();
@ -943,7 +942,9 @@ impl Transaction {
.with_get("status", |t: &mut Transaction| t.status.clone()) .with_get("status", |t: &mut Transaction| t.status.clone())
.with_get("server_number", |t: &mut Transaction| t.server_number) .with_get("server_number", |t: &mut Transaction| t.server_number)
.with_get("server_ip", |t: &mut Transaction| t.server_ip.clone()) .with_get("server_ip", |t: &mut Transaction| t.server_ip.clone())
.with_get("authorized_key", |t: &mut Transaction| t.authorized_key.clone()) .with_get("authorized_key", |t: &mut Transaction| {
t.authorized_key.clone()
})
.with_get("host_key", |t: &mut Transaction| t.host_key.clone()) .with_get("host_key", |t: &mut Transaction| t.host_key.clone())
.with_get("comment", |t: &mut Transaction| t.comment.clone()) .with_get("comment", |t: &mut Transaction| t.comment.clone())
.with_get("product", |t: &mut Transaction| t.product.clone()) .with_get("product", |t: &mut Transaction| t.product.clone())
@ -968,7 +969,9 @@ impl TransactionProduct {
.with_name("TransactionProduct") .with_name("TransactionProduct")
.with_get("id", |p: &mut TransactionProduct| p.id.clone()) .with_get("id", |p: &mut TransactionProduct| p.id.clone())
.with_get("name", |p: &mut TransactionProduct| p.name.clone()) .with_get("name", |p: &mut TransactionProduct| p.name.clone())
.with_get("description", |p: &mut TransactionProduct| p.description.clone()) .with_get("description", |p: &mut TransactionProduct| {
p.description.clone()
})
.with_get("traffic", |p: &mut TransactionProduct| p.traffic.clone()) .with_get("traffic", |p: &mut TransactionProduct| p.traffic.clone())
.with_get("dist", |p: &mut TransactionProduct| p.dist.clone()) .with_get("dist", |p: &mut TransactionProduct| p.dist.clone())
.with_get("arch", |p: &mut TransactionProduct| p.arch.clone()) .with_get("arch", |p: &mut TransactionProduct| p.arch.clone())
@ -1016,7 +1019,11 @@ pub struct AuctionServerProduct {
pub traffic: String, pub traffic: String,
#[serde(deserialize_with = "string_or_seq_string")] #[serde(deserialize_with = "string_or_seq_string")]
pub dist: Vec<String>, pub dist: Vec<String>,
#[serde(rename = "@deprecated arch", default, deserialize_with = "option_string_or_seq_string")] #[serde(
rename = "@deprecated arch",
default,
deserialize_with = "option_string_or_seq_string"
)]
#[deprecated(note = "use `dist` instead")] #[deprecated(note = "use `dist` instead")]
pub arch: Option<Vec<String>>, pub arch: Option<Vec<String>>,
#[serde(deserialize_with = "string_or_seq_string")] #[serde(deserialize_with = "string_or_seq_string")]
@ -1050,29 +1057,53 @@ impl AuctionServerProduct {
.with_name("AuctionServerProduct") .with_name("AuctionServerProduct")
.with_get("id", |p: &mut AuctionServerProduct| p.id) .with_get("id", |p: &mut AuctionServerProduct| p.id)
.with_get("name", |p: &mut AuctionServerProduct| p.name.clone()) .with_get("name", |p: &mut AuctionServerProduct| p.name.clone())
.with_get("description", |p: &mut AuctionServerProduct| p.description.clone()) .with_get("description", |p: &mut AuctionServerProduct| {
p.description.clone()
})
.with_get("traffic", |p: &mut AuctionServerProduct| p.traffic.clone()) .with_get("traffic", |p: &mut AuctionServerProduct| p.traffic.clone())
.with_get("dist", |p: &mut AuctionServerProduct| p.dist.clone()) .with_get("dist", |p: &mut AuctionServerProduct| p.dist.clone())
.with_get("arch", |p: &mut AuctionServerProduct| p.arch.clone()) .with_get("arch", |p: &mut AuctionServerProduct| p.arch.clone())
.with_get("lang", |p: &mut AuctionServerProduct| p.lang.clone()) .with_get("lang", |p: &mut AuctionServerProduct| p.lang.clone())
.with_get("cpu", |p: &mut AuctionServerProduct| p.cpu.clone()) .with_get("cpu", |p: &mut AuctionServerProduct| p.cpu.clone())
.with_get("cpu_benchmark", |p: &mut AuctionServerProduct| p.cpu_benchmark) .with_get("cpu_benchmark", |p: &mut AuctionServerProduct| {
p.cpu_benchmark
})
.with_get("memory_size", |p: &mut AuctionServerProduct| p.memory_size) .with_get("memory_size", |p: &mut AuctionServerProduct| p.memory_size)
.with_get("hdd_size", |p: &mut AuctionServerProduct| p.hdd_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_text", |p: &mut AuctionServerProduct| {
p.hdd_text.clone()
})
.with_get("hdd_count", |p: &mut AuctionServerProduct| p.hdd_count) .with_get("hdd_count", |p: &mut AuctionServerProduct| p.hdd_count)
.with_get("datacenter", |p: &mut AuctionServerProduct| p.datacenter.clone()) .with_get("datacenter", |p: &mut AuctionServerProduct| {
.with_get("network_speed", |p: &mut AuctionServerProduct| p.network_speed.clone()) 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", |p: &mut AuctionServerProduct| p.price.clone())
.with_get("price_hourly", |p: &mut AuctionServerProduct| p.price_hourly.clone()) .with_get("price_hourly", |p: &mut AuctionServerProduct| {
.with_get("price_setup", |p: &mut AuctionServerProduct| p.price_setup.clone()) p.price_hourly.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", |p: &mut AuctionServerProduct| {
.with_get("price_setup_with_vat", |p: &mut AuctionServerProduct| p.price_setup_with_vat.clone()) 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("fixed_price", |p: &mut AuctionServerProduct| p.fixed_price)
.with_get("next_reduce", |p: &mut AuctionServerProduct| p.next_reduce) .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("next_reduce_date", |p: &mut AuctionServerProduct| {
.with_get("orderable_addons", |p: &mut AuctionServerProduct| p.orderable_addons.clone()) p.next_reduce_date.clone()
})
.with_get("orderable_addons", |p: &mut AuctionServerProduct| {
p.orderable_addons.clone()
})
.on_print(|p: &mut AuctionServerProduct| p.to_string()) .on_print(|p: &mut AuctionServerProduct| p.to_string())
.with_fn("pretty_print", |p: &mut AuctionServerProduct| p.to_string()); .with_fn("pretty_print", |p: &mut AuctionServerProduct| p.to_string());
} }
@ -1087,7 +1118,10 @@ impl fmt::Display for AuctionServerProduct {
table.add_row(row!["Description", self.description.join(", ")]); table.add_row(row!["Description", self.description.join(", ")]);
table.add_row(row!["Traffic", self.traffic.clone()]); table.add_row(row!["Traffic", self.traffic.clone()]);
table.add_row(row!["Distributions", self.dist.join(", ")]); 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![
"Architectures",
self.arch.as_deref().unwrap_or_default().join(", ")
]);
table.add_row(row!["Languages", self.lang.join(", ")]); table.add_row(row!["Languages", self.lang.join(", ")]);
table.add_row(row!["CPU", self.cpu.clone()]); table.add_row(row!["CPU", self.cpu.clone()]);
table.add_row(row!["CPU Benchmark", self.cpu_benchmark.to_string()]); table.add_row(row!["CPU Benchmark", self.cpu_benchmark.to_string()]);
@ -1098,10 +1132,19 @@ impl fmt::Display for AuctionServerProduct {
table.add_row(row!["Datacenter", self.datacenter.clone()]); table.add_row(row!["Datacenter", self.datacenter.clone()]);
table.add_row(row!["Network Speed", self.network_speed.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 (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 (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 (Setup Net)", self.price_setup.clone()]);
table.add_row(row!["Price (VAT)", self.price_with_vat.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 (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!["Price (Setup VAT)", self.price_setup_with_vat.clone()]);
table.add_row(row!["Fixed Price", self.fixed_price.to_string()]); 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 (seconds)", self.next_reduce.to_string()]);
@ -1165,7 +1208,7 @@ pub struct AuctionTransactionProduct {
pub traffic: String, pub traffic: String,
pub dist: String, pub dist: String,
#[serde(rename = "@deprecated arch")] #[serde(rename = "@deprecated arch")]
pub arch: String, pub arch: Option<String>,
pub lang: String, pub lang: String,
pub cpu: String, pub cpu: String,
pub cpu_benchmark: i32, pub cpu_benchmark: i32,
@ -1175,9 +1218,9 @@ pub struct AuctionTransactionProduct {
pub hdd_count: i32, pub hdd_count: i32,
pub datacenter: String, pub datacenter: String,
pub network_speed: String, pub network_speed: String,
pub fixed_price: bool, pub fixed_price: Option<bool>,
pub next_reduce: i32, pub next_reduce: Option<i32>,
pub next_reduce_date: String, pub next_reduce_date: Option<String>,
} }
impl AuctionTransaction { impl AuctionTransaction {
@ -1187,38 +1230,21 @@ impl AuctionTransaction {
.with_get("id", |t: &mut AuctionTransaction| t.id.clone()) .with_get("id", |t: &mut AuctionTransaction| t.id.clone())
.with_get("date", |t: &mut AuctionTransaction| t.date.clone()) .with_get("date", |t: &mut AuctionTransaction| t.date.clone())
.with_get("status", |t: &mut AuctionTransaction| t.status.clone()) .with_get("status", |t: &mut AuctionTransaction| t.status.clone())
.with_get("server_number", |t: &mut AuctionTransaction| t.server_number) .with_get("server_number", |t: &mut AuctionTransaction| {
.with_get("server_ip", |t: &mut AuctionTransaction| t.server_ip.clone()) t.server_number
.with_get("authorized_key", |t: &mut AuctionTransaction| t.authorized_key.clone()) })
.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("host_key", |t: &mut AuctionTransaction| t.host_key.clone())
.with_get("comment", |t: &mut AuctionTransaction| t.comment.clone()) .with_get("comment", |t: &mut AuctionTransaction| t.comment.clone())
.with_get("product", |t: &mut AuctionTransaction| t.product.clone()) .with_get("product", |t: &mut AuctionTransaction| t.product.clone())
.with_get("addons", |t: &mut AuctionTransaction| t.addons.clone()); .with_get("addons", |t: &mut AuctionTransaction| t.addons.clone())
} .on_print(|t: &mut AuctionTransaction| t.to_string())
} .with_fn("pretty_print", |t: &mut AuctionTransaction| t.to_string());
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());
} }
} }
@ -1237,7 +1263,7 @@ impl fmt::Display for AuctionTransaction {
table.add_row(row!["Product Description", self.product.description.join(", ")]); 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 Traffic", self.product.traffic.clone()]);
table.add_row(row!["Product Distributions", self.product.dist.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 Architectures", self.product.arch.as_deref().unwrap_or("N/A")]);
table.add_row(row!["Product Languages", self.product.lang.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", self.product.cpu.clone()]);
table.add_row(row!["Product CPU Benchmark", self.product.cpu_benchmark.to_string()]); table.add_row(row!["Product CPU Benchmark", self.product.cpu_benchmark.to_string()]);
@ -1247,9 +1273,9 @@ impl fmt::Display for AuctionTransaction {
table.add_row(row!["Product HDD Count", self.product.hdd_count.to_string()]); 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 Datacenter", self.product.datacenter.clone()]);
table.add_row(row!["Product Network Speed", self.product.network_speed.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 Fixed Price", self.product.fixed_price.unwrap_or_default().to_string()]);
table.add_row(row!["Product Next Reduce (seconds)", self.product.next_reduce.to_string()]); table.add_row(row!["Product Next Reduce (seconds)", self.product.next_reduce.map_or("N/A".to_string(), |r| r.to_string())]);
table.add_row(row!["Product Next Reduce Date", self.product.next_reduce_date.clone()]); table.add_row(row!["Product Next Reduce Date", self.product.next_reduce_date.as_deref().unwrap_or("N/A")]);
table.add_row(row!["Addons", self.addons.join(", ")]); table.add_row(row!["Addons", self.addons.join(", ")]);
let mut authorized_keys_table = Table::new(); let mut authorized_keys_table = Table::new();
@ -1267,14 +1293,144 @@ impl fmt::Display for AuctionTransaction {
let mut host_keys_table = Table::new(); let mut host_keys_table = Table::new();
host_keys_table.add_row(row![b => "Fingerprint", "Type", "Size"]); host_keys_table.add_row(row![b => "Fingerprint", "Type", "Size"]);
for key in &self.host_key { for key in &self.host_key {
host_keys_table.add_row(row![ host_keys_table.add_row(row![key.key.fingerprint, key.key.key_type, key.key.size]);
key.key.fingerprint,
key.key.key_type,
key.key.size
]);
} }
table.add_row(row!["Host Keys", host_keys_table]); table.add_row(row!["Host Keys", host_keys_table]);
write!(f, "{}", table) write!(f, "{}", table)
} }
} }
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().unwrap_or_default()
})
.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.unwrap_or_default()
})
.with_get("next_reduce", |p: &mut AuctionTransactionProduct| {
p.next_reduce.unwrap_or_default()
})
.with_get("next_reduce_date", |p: &mut AuctionTransactionProduct| {
p.next_reduce_date.clone().unwrap_or_default()
});
}
}
#[derive(Debug, Deserialize, Clone, CustomType)]
#[rhai_type(extra = Self::build_rhai_type)]
pub struct OrderAuctionServerBuilder {
pub product_id: i64,
pub authorized_keys: Option<Vec<String>>,
pub dist: Option<String>,
pub lang: Option<String>,
pub comment: Option<String>,
pub addon: Option<Vec<String>>,
pub test: Option<bool>,
}
impl OrderAuctionServerBuilder {
pub fn new(product_id: i64) -> Self {
Self {
product_id,
authorized_keys: None,
dist: None,
lang: None,
comment: None,
addon: None,
// by default test is enabled
test: Some(true),
}
}
pub fn with_authorized_keys(mut self, keys: Array) -> Self {
let authorized_keys: Vec<String> = if keys.is_empty() {
vec![]
} else if keys[0].is::<SshKey>() {
keys.into_iter()
.map(|k| k.cast::<SshKey>().fingerprint)
.collect()
} else {
keys.into_iter().map(|k| k.into_string().unwrap()).collect()
};
self.authorized_keys = Some(authorized_keys);
self
}
pub fn with_dist(mut self, dist: &str) -> Self {
self.dist = Some(dist.to_string());
self
}
pub fn with_lang(mut self, lang: &str) -> Self {
self.lang = Some(lang.to_string());
self
}
pub fn with_comment(mut self, comment: &str) -> Self {
self.comment = Some(comment.to_string());
self
}
pub fn with_addon(mut self, addon: Array) -> Self {
let addons = addon
.into_iter()
.map(|a| a.into_string().unwrap())
.collect();
self.addon = Some(addons);
self
}
pub fn with_test(mut self, test: bool) -> Self {
self.test = Some(test);
self
}
fn build_rhai_type(builder: &mut TypeBuilder<Self>) {
builder
.with_name("OrderAuctionServerBuilder")
.with_fn("new_auction_server_builder", Self::new)
.with_fn("with_authorized_keys", Self::with_authorized_keys)
.with_fn("with_dist", Self::with_dist)
.with_fn("with_lang", Self::with_lang)
.with_fn("with_comment", Self::with_comment)
.with_fn("with_addon", Self::with_addon)
.with_fn("with_test", Self::with_test)
// TODO implement other getters
.with_get("comment", |b: &mut OrderAuctionServerBuilder| {
b.comment.clone().unwrap_or("".to_string())
});
}
}

View File

@ -1,8 +1,6 @@
use crate::api::Client; use crate::api::Client;
use crate::api::models::{ use crate::api::models::{
AuctionServerProduct, AuctionTransaction, AuctionTransactionProduct, AuthorizedKey, Boot, AuctionServerProduct, AuctionTransaction, AuctionTransactionProduct, AuthorizedKey, Boot, Cancellation, Cpanel, HostKey, Linux, OrderAuctionServerBuilder, OrderServerProduct, Plesk, Rescue, Server, SshKey, Transaction, TransactionProduct, Vnc, Windows
Cancellation, Cpanel, HostKey, Linux, OrderServerProduct, Plesk, Rescue, Server, SshKey,
Transaction, TransactionProduct, Vnc, Windows,
}; };
use rhai::{Engine, Scope}; use rhai::{Engine, Scope};
@ -34,6 +32,7 @@ pub fn setup_engine(client: Client) -> (Engine, Scope<'static>) {
engine.build_type::<AuctionServerProduct>(); engine.build_type::<AuctionServerProduct>();
engine.build_type::<AuctionTransaction>(); engine.build_type::<AuctionTransaction>();
engine.build_type::<AuctionTransactionProduct>(); engine.build_type::<AuctionTransactionProduct>();
engine.build_type::<OrderAuctionServerBuilder>();
server::register(&mut engine); server::register(&mut engine);
ssh_keys::register(&mut engine); ssh_keys::register(&mut engine);

View File

@ -157,7 +157,7 @@ pub fn pretty_print_auction_transactions(transactions: rhai::Array) {
for transaction_dyn in transactions { for transaction_dyn in transactions {
if let Some(transaction) = transaction_dyn.try_cast::<crate::api::models::AuctionTransaction>() { if let Some(transaction) = transaction_dyn.try_cast::<crate::api::models::AuctionTransaction>() {
let authorized_keys_table = { let _authorized_keys_table = {
let mut table = Table::new(); let mut table = Table::new();
table.add_row(row![b => "Name", "Fingerprint", "Type", "Size"]); table.add_row(row![b => "Name", "Fingerprint", "Type", "Size"]);
for key in &transaction.authorized_key { for key in &transaction.authorized_key {
@ -171,7 +171,7 @@ pub fn pretty_print_auction_transactions(transactions: rhai::Array) {
table table
}; };
let host_keys_table = { let _host_keys_table = {
let mut table = Table::new(); let mut table = Table::new();
table.add_row(row![b => "Fingerprint", "Type", "Size"]); table.add_row(row![b => "Fingerprint", "Type", "Size"]);
for key in &transaction.host_key { for key in &transaction.host_key {
@ -195,7 +195,7 @@ pub fn pretty_print_auction_transactions(transactions: rhai::Array) {
transaction.product.name, transaction.product.name,
transaction.product.traffic, transaction.product.traffic,
transaction.product.dist, transaction.product.dist,
transaction.product.arch, transaction.product.arch.as_deref().unwrap_or("N/A"),
transaction.product.lang, transaction.product.lang,
transaction.product.cpu, transaction.product.cpu,
transaction.product.cpu_benchmark, transaction.product.cpu_benchmark,
@ -205,9 +205,16 @@ pub fn pretty_print_auction_transactions(transactions: rhai::Array) {
transaction.product.hdd_count, transaction.product.hdd_count,
transaction.product.datacenter, transaction.product.datacenter,
transaction.product.network_speed, transaction.product.network_speed,
transaction.product.fixed_price, transaction.product.fixed_price.unwrap_or_default().to_string(),
transaction.product.next_reduce, transaction
transaction.product.next_reduce_date, .product
.next_reduce
.map_or("N/A".to_string(), |r| r.to_string()),
transaction
.product
.next_reduce_date
.as_deref()
.unwrap_or("N/A"),
transaction.addons.join(", "), transaction.addons.join(", "),
]); ]);
} }

View File

@ -67,7 +67,6 @@ pub mod server_api {
pub fn withdraw_cancellation( pub fn withdraw_cancellation(
client: &mut Client, client: &mut Client,
server_number: i64, server_number: i64,
cancellation_date: &str,
) -> Result<(), Box<EvalAltResult>> { ) -> Result<(), Box<EvalAltResult>> {
client client
.withdraw_cancellation(server_number as i32) .withdraw_cancellation(server_number as i32)

View File

@ -11,6 +11,7 @@ pub fn register(engine: &mut Engine) {
#[export_module] #[export_module]
pub mod server_order_api { pub mod server_order_api {
use crate::api::models::OrderAuctionServerBuilder;
#[rhai_fn(name = "get_server_products", return_raw)] #[rhai_fn(name = "get_server_products", return_raw)]
pub fn get_server_ordering_product_overview( pub fn get_server_ordering_product_overview(
@ -133,52 +134,19 @@ pub mod server_order_api {
#[rhai_fn(name = "order_auction_server", return_raw)] #[rhai_fn(name = "order_auction_server", return_raw)]
pub fn order_auction_server( pub fn order_auction_server(
client: &mut Client, client: &mut Client,
product_id: i32, order: OrderAuctionServerBuilder,
authorized_keys: Array,
dist: Option<String>,
arch: Option<String>,
lang: Option<String>,
comment: Option<String>,
addons: Array,
test: Option<bool>,
) -> Result<AuctionTransaction, Box<EvalAltResult>> { ) -> Result<AuctionTransaction, Box<EvalAltResult>> {
let authorized_keys: Vec<String> = if authorized_keys.is_empty() { println!("Builder struct being used to order server: {:#?}", order);
vec![] let transaction = client.order_auction_server(
} else if authorized_keys[0].is::<SshKey>() { order.product_id,
authorized_keys order.authorized_keys.unwrap_or(vec![]),
.into_iter() order.dist,
.map(|k| k.cast::<SshKey>().fingerprint) None,
.collect() order.lang,
} else { order.comment,
authorized_keys order.addon,
.into_iter() order.test,
.map(|k| k.into_string().unwrap()) ).map_err(|e| Into::<Box<EvalAltResult>>::into(e.to_string()))?;
.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) Ok(transaction)
} }
} }