From 721f9182700ac7c8379b900fe6c5f80653fe4afa Mon Sep 17 00:00:00 2001 From: Maxime Van Hees Date: Wed, 23 Jul 2025 15:33:33 +0200 Subject: [PATCH] added all requirements to order auction server + tested it --- examples/server_ordering.rhai | 29 +- src/api/mod.rs | 29 +- src/api/models.rs | 348 +++++++++++++----- src/scripting/mod.rs | 5 +- .../printing/server_ordering_table.rs | 19 +- src/scripting/server.rs | 1 - src/scripting/server_ordering.rs | 58 +-- 7 files changed, 312 insertions(+), 177 deletions(-) diff --git a/examples/server_ordering.rhai b/examples/server_ordering.rhai index 997267d..e688644 100644 --- a/examples/server_ordering.rhai +++ b/examples/server_ordering.rhai @@ -27,22 +27,23 @@ // 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); +// let auctioned_server = hetzner.get_auction_server_product_by_id("2739642"); +// 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) - (), // arch (Option) - (), // lang (Option) - (), // comment (Option) - [], // addons (Array) - (), // test (Option) -); -print(transaction); +// 2. Use the builder to bundle the details on what to order +// let order_builder = new_auction_server_builder(2741558) +// .with_authorized_keys([ssh_key.fingerprint]) +// .with_lang("en") +// .with_comment("test") +// .with_test(false); +// 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) \ No newline at end of file diff --git a/src/api/mod.rs b/src/api/mod.rs index 6391506..c4aced5 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -378,7 +378,7 @@ impl Client { } pub fn order_auction_server( &self, - product_id: i32, + product_id: i64, authorized_keys: Vec, dist: Option, arch: Option, @@ -387,35 +387,40 @@ impl Client { addons: Option>, test: Option, ) -> Result { - let mut params = json!({ - "product_id": product_id, - "authorized_key": authorized_keys, - }); + let mut params: Vec<(&str, String)> = Vec::new(); + + params.push(("product_id", product_id.to_string())); + + for key in &authorized_keys { + params.push(("authorized_key[]", key.clone())); + } if let Some(dist) = dist { - params["dist"] = json!(dist); + params.push(("dist", dist)); } if let Some(arch) = arch { - params["@deprecated arch"] = json!(arch); + params.push(("@deprecated arch", arch)); } if let Some(lang) = lang { - params["lang"] = json!(lang); + params.push(("lang", lang)); } if let Some(comment) = comment { - params["comment"] = json!(comment); + params.push(("comment", comment)); } if let Some(addons) = addons { - params["addon"] = json!(addons); + for addon in addons { + params.push(("addon[]", addon)); + } } if let Some(test) = test { - params["test"] = json!(test); + params.push(("test", test.to_string())); } 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(¶ms) + .form(¶ms) .send()?; let wrapped: AuctionTransactionWrapper = self.handle_response(response)?; diff --git a/src/api/models.rs b/src/api/models.rs index f6448f0..43db3e0 100644 --- a/src/api/models.rs +++ b/src/api/models.rs @@ -1,8 +1,8 @@ -use rhai::{CustomType, TypeBuilder}; +use prettytable::{Table, row}; +use rhai::{Array, CustomType, TypeBuilder}; use serde::{Deserialize, Deserializer}; use serde_json::Value; use std::fmt; -use prettytable::{row, Table}; #[derive(Debug, Deserialize, Clone)] pub struct ServerWrapper { @@ -40,7 +40,9 @@ impl Server { builder .with_name("Server") .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_name", |s: &mut Server| s.server_name.clone()) .with_get("product", |s: &mut Server| s.product.clone()) @@ -152,13 +154,7 @@ impl SshKey { impl fmt::Display for SshKey { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut table = Table::new(); - table.add_row(row![ - "Name", - "Fingerprint", - "Type", - "Size", - "Created At" - ]); + table.add_row(row!["Name", "Fingerprint", "Type", "Size", "Created At"]); table.add_row(row![ self.name.clone(), self.fingerprint.clone(), @@ -251,9 +247,7 @@ impl Rescue { .with_get("os", |r: &mut Rescue| r.os.clone()) .with_get("active", |r: &mut Rescue| r.active) .with_get("password", |r: &mut Rescue| r.password.clone()) - .with_get("authorized_key", |r: &mut Rescue| { - r.authorized_key.clone() - }) + .with_get("authorized_key", |r: &mut Rescue| r.authorized_key.clone()) .with_get("host_key", |r: &mut Rescue| r.host_key.clone()) .on_print(|r: &mut Rescue| r.to_string()) .with_fn("pretty_print", |r: &mut Rescue| r.to_string()); @@ -293,17 +287,13 @@ impl Linux { builder .with_name("Linux") .with_get("server_ip", |l: &mut Linux| l.server_ip.clone()) - .with_get("server_ipv6_net", |l: &mut Linux| { - l.server_ipv6_net.clone() - }) + .with_get("server_ipv6_net", |l: &mut Linux| l.server_ipv6_net.clone()) .with_get("server_number", |l: &mut Linux| l.server_number) .with_get("dist", |l: &mut Linux| l.dist.clone()) .with_get("lang", |l: &mut Linux| l.lang.clone()) .with_get("active", |l: &mut Linux| l.active) .with_get("password", |l: &mut Linux| l.password.clone()) - .with_get("authorized_key", |l: &mut Linux| { - l.authorized_key.clone() - }) + .with_get("authorized_key", |l: &mut Linux| l.authorized_key.clone()) .with_get("host_key", |l: &mut Linux| l.host_key.clone()) .on_print(|l: &mut Linux| l.to_string()) .with_fn("pretty_print", |l: &mut Linux| l.to_string()); @@ -428,9 +418,7 @@ impl Plesk { builder .with_name("Plesk") .with_get("server_ip", |p: &mut Plesk| p.server_ip.clone()) - .with_get("server_ipv6_net", |p: &mut Plesk| { - p.server_ipv6_net.clone() - }) + .with_get("server_ipv6_net", |p: &mut Plesk| p.server_ipv6_net.clone()) .with_get("server_number", |p: &mut Plesk| p.server_number) .with_get("dist", |p: &mut Plesk| p.dist.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 IPv6 Net", - self.server_ipv6_net - .as_deref() - .unwrap_or("N/A") - .to_string() + self.server_ipv6_net.as_deref().unwrap_or("N/A").to_string() ]); table.add_row(row!["Server Number", self.server_number.to_string()]); table.add_row(row!["Server Name", self.server_name.clone()]); @@ -570,7 +555,10 @@ impl fmt::Display for Cancellation { self.earliest_cancellation_date.clone() ]); 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![ "Cancellation Date", @@ -608,9 +596,7 @@ where } } -fn option_string_or_seq_string<'de, D>( - deserializer: D, -) -> Result>, D::Error> +fn option_string_or_seq_string<'de, D>(deserializer: D) -> Result>, D::Error> where D: Deserializer<'de>, { @@ -645,7 +631,9 @@ impl From for ApiError { fn from(value: reqwest::blocking::Response) -> Self { ApiError { 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, #[serde(deserialize_with = "string_or_seq_string")] pub dist: Vec, - #[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")] pub arch: Option>, #[serde(deserialize_with = "string_or_seq_string")] @@ -805,14 +797,18 @@ impl OrderServerProduct { .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("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()) + .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()); } @@ -827,7 +823,10 @@ impl fmt::Display for OrderServerProduct { 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![ + "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(", ")]); let mut prices_table = Table::new(); @@ -943,7 +942,9 @@ impl Transaction { .with_get("status", |t: &mut Transaction| t.status.clone()) .with_get("server_number", |t: &mut Transaction| t.server_number) .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("comment", |t: &mut Transaction| t.comment.clone()) .with_get("product", |t: &mut Transaction| t.product.clone()) @@ -968,7 +969,9 @@ impl TransactionProduct { .with_name("TransactionProduct") .with_get("id", |p: &mut TransactionProduct| p.id.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("dist", |p: &mut TransactionProduct| p.dist.clone()) .with_get("arch", |p: &mut TransactionProduct| p.arch.clone()) @@ -1016,7 +1019,11 @@ pub struct AuctionServerProduct { pub traffic: String, #[serde(deserialize_with = "string_or_seq_string")] pub dist: Vec, - #[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")] pub arch: Option>, #[serde(deserialize_with = "string_or_seq_string")] @@ -1050,29 +1057,53 @@ impl AuctionServerProduct { .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("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("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_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("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("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()) + .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()); } @@ -1087,7 +1118,10 @@ impl fmt::Display for AuctionServerProduct { 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![ + "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()]); @@ -1098,10 +1132,19 @@ impl fmt::Display for AuctionServerProduct { 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 (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 (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()]); @@ -1165,7 +1208,7 @@ pub struct AuctionTransactionProduct { pub traffic: String, pub dist: String, #[serde(rename = "@deprecated arch")] - pub arch: String, + pub arch: Option, pub lang: String, pub cpu: String, pub cpu_benchmark: i32, @@ -1175,9 +1218,9 @@ pub struct AuctionTransactionProduct { pub hdd_count: i32, pub datacenter: String, pub network_speed: String, - pub fixed_price: bool, - pub next_reduce: i32, - pub next_reduce_date: String, + pub fixed_price: Option, + pub next_reduce: Option, + pub next_reduce_date: Option, } impl AuctionTransaction { @@ -1187,38 +1230,21 @@ impl 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("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) { - 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()); + .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()); } } @@ -1237,7 +1263,7 @@ impl fmt::Display for AuctionTransaction { 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 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 CPU", self.product.cpu.clone()]); 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 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!["Product Fixed Price", self.product.fixed_price.unwrap_or_default().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.as_deref().unwrap_or("N/A")]); table.add_row(row!["Addons", self.addons.join(", ")]); let mut authorized_keys_table = Table::new(); @@ -1267,14 +1293,144 @@ impl fmt::Display for AuctionTransaction { 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 - ]); + 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) } -} \ No newline at end of file +} + +impl AuctionTransactionProduct { + fn build_rhai_type(builder: &mut TypeBuilder) { + 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>, + pub dist: Option, + pub lang: Option, + pub comment: Option, + pub addon: Option>, + pub test: Option, +} + +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 = if keys.is_empty() { + vec![] + } else if keys[0].is::() { + keys.into_iter() + .map(|k| k.cast::().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) { + 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()) + }); + } +} diff --git a/src/scripting/mod.rs b/src/scripting/mod.rs index 43d3fc2..1059742 100644 --- a/src/scripting/mod.rs +++ b/src/scripting/mod.rs @@ -1,8 +1,6 @@ use crate::api::Client; use crate::api::models::{ - AuctionServerProduct, AuctionTransaction, AuctionTransactionProduct, AuthorizedKey, Boot, - Cancellation, Cpanel, HostKey, Linux, OrderServerProduct, Plesk, Rescue, Server, SshKey, - Transaction, TransactionProduct, Vnc, Windows, + AuctionServerProduct, AuctionTransaction, AuctionTransactionProduct, AuthorizedKey, Boot, Cancellation, Cpanel, HostKey, Linux, OrderAuctionServerBuilder, OrderServerProduct, Plesk, Rescue, Server, SshKey, Transaction, TransactionProduct, Vnc, Windows }; use rhai::{Engine, Scope}; @@ -34,6 +32,7 @@ pub fn setup_engine(client: Client) -> (Engine, Scope<'static>) { engine.build_type::(); engine.build_type::(); engine.build_type::(); + engine.build_type::(); server::register(&mut engine); ssh_keys::register(&mut engine); diff --git a/src/scripting/printing/server_ordering_table.rs b/src/scripting/printing/server_ordering_table.rs index 1c4863d..2346923 100644 --- a/src/scripting/printing/server_ordering_table.rs +++ b/src/scripting/printing/server_ordering_table.rs @@ -157,7 +157,7 @@ pub fn pretty_print_auction_transactions(transactions: rhai::Array) { for transaction_dyn in transactions { if let Some(transaction) = transaction_dyn.try_cast::() { - let authorized_keys_table = { + let _authorized_keys_table = { let mut table = Table::new(); table.add_row(row![b => "Name", "Fingerprint", "Type", "Size"]); for key in &transaction.authorized_key { @@ -171,7 +171,7 @@ pub fn pretty_print_auction_transactions(transactions: rhai::Array) { table }; - let host_keys_table = { + let _host_keys_table = { let mut table = Table::new(); table.add_row(row![b => "Fingerprint", "Type", "Size"]); for key in &transaction.host_key { @@ -195,7 +195,7 @@ pub fn pretty_print_auction_transactions(transactions: rhai::Array) { transaction.product.name, transaction.product.traffic, transaction.product.dist, - transaction.product.arch, + transaction.product.arch.as_deref().unwrap_or("N/A"), transaction.product.lang, transaction.product.cpu, transaction.product.cpu_benchmark, @@ -205,9 +205,16 @@ pub fn pretty_print_auction_transactions(transactions: rhai::Array) { 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.product.fixed_price.unwrap_or_default().to_string(), + transaction + .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(", "), ]); } diff --git a/src/scripting/server.rs b/src/scripting/server.rs index da22519..321bf18 100644 --- a/src/scripting/server.rs +++ b/src/scripting/server.rs @@ -67,7 +67,6 @@ pub mod server_api { pub fn withdraw_cancellation( client: &mut Client, server_number: i64, - cancellation_date: &str, ) -> Result<(), Box> { client .withdraw_cancellation(server_number as i32) diff --git a/src/scripting/server_ordering.rs b/src/scripting/server_ordering.rs index c7db42c..4fb5883 100644 --- a/src/scripting/server_ordering.rs +++ b/src/scripting/server_ordering.rs @@ -11,6 +11,7 @@ pub fn register(engine: &mut Engine) { #[export_module] pub mod server_order_api { + use crate::api::models::OrderAuctionServerBuilder; #[rhai_fn(name = "get_server_products", return_raw)] pub fn get_server_ordering_product_overview( @@ -133,52 +134,19 @@ pub mod server_order_api { #[rhai_fn(name = "order_auction_server", return_raw)] pub fn order_auction_server( client: &mut Client, - product_id: i32, - authorized_keys: Array, - dist: Option, - arch: Option, - lang: Option, - comment: Option, - addons: Array, - test: Option, + order: OrderAuctionServerBuilder, ) -> Result> { - let authorized_keys: Vec = if authorized_keys.is_empty() { - vec![] - } else if authorized_keys[0].is::() { - authorized_keys - .into_iter() - .map(|k| k.cast::().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::>::into(e.to_string()))?; + println!("Builder struct being used to order server: {:#?}", order); + let transaction = client.order_auction_server( + order.product_id, + order.authorized_keys.unwrap_or(vec![]), + order.dist, + None, + order.lang, + order.comment, + order.addon, + order.test, + ).map_err(|e| Into::>::into(e.to_string()))?; Ok(transaction) } }