@@ -1,6 +1,6 @@ | |||
[package] | |||
name = "libfj" | |||
version = "0.7.2" | |||
version = "0.7.3" | |||
authors = ["NGnius (Graham) <ngniusness@gmail.com>"] | |||
edition = "2018" | |||
description = "An unofficial collection of APIs used in FreeJam games and mods" | |||
@@ -4,7 +4,7 @@ use reqwest::{Client, Error as ReqwestError, Response}; | |||
use url::{Url}; | |||
use crate::robocraft2::{ITokenProvider, ErrorPayload}; | |||
use crate::robocraft2::{SearchPayload, SearchResponse, CreateRobotPayload, CreateRobotResponse, FactoryInfoResponse, PublishRobotPayload, PublishRobotResponse, MyRobotsResponse, GetRobotResponse}; | |||
use crate::robocraft2::{SearchPayload, SearchResponse, CreateRobotPayload, CreateRobotResponse, FactoryInfoResponse, PublishRobotPayload, PublishRobotResponse, MyRobotsResponse, GetRobotResponse, ModerateRobotPayload, ReportRobotPayload}; | |||
/// Community Factory Robot 2 root URL | |||
pub const FACTORY_DOMAIN: &str = "https://factory.production.robocraft2.com"; | |||
@@ -254,4 +254,34 @@ impl FactoryAPI { | |||
.map_err(FactoryError::Protocol)?; | |||
handle_json_response::<GetRobotResponse>(result).await | |||
} | |||
pub async fn moderate(&self, payload: ModerateRobotPayload, id: String) -> Result<(), FactoryError> { | |||
let url = Url::parse(FACTORY_DOMAIN) | |||
.unwrap() | |||
.join(&format!("/v1/foundry/vehicles/{}/moderate", id)) | |||
.unwrap(); | |||
let token = self.token.lock().unwrap().token().await.map_err(FactoryError::Protocol)?; | |||
let _result = self.client.post(url) | |||
.header("Authorization", "Bearer ".to_owned() + &token) | |||
.header("Content-Type", "application/json") | |||
.json(&payload) | |||
.send().await | |||
.map_err(FactoryError::Protocol)?; | |||
Ok(()) | |||
} | |||
pub async fn report(&self, payload: ReportRobotPayload, id: String) -> Result<(), FactoryError> { | |||
let url = Url::parse(FACTORY_DOMAIN) | |||
.unwrap() | |||
.join(&format!("/v1/foundry/vehicles/{}/report", id)) | |||
.unwrap(); | |||
let token = self.token.lock().unwrap().token().await.map_err(FactoryError::Protocol)?; | |||
let _result = self.client.post(url) | |||
.header("Authorization", "Bearer ".to_owned() + &token) | |||
.header("Content-Type", "application/json") | |||
.json(&payload) | |||
.send().await | |||
.map_err(FactoryError::Protocol)?; | |||
Ok(()) | |||
} | |||
} |
@@ -244,3 +244,25 @@ pub struct GetRobotResponse { | |||
#[serde(rename = "created")] | |||
pub created: String, // date | |||
} | |||
// moderate robot endpoint | |||
#[derive(Deserialize, Serialize, Clone, Debug)] | |||
pub struct ModerateRobotPayload { | |||
#[serde(rename = "approve")] | |||
pub approve: bool, | |||
#[serde(rename = "reason")] | |||
pub reason: String, | |||
} | |||
// (no response) | |||
// report robot endpoint | |||
#[derive(Deserialize, Serialize, Clone, Debug)] | |||
pub struct ReportRobotPayload { | |||
#[serde(rename = "reason")] | |||
pub reason: String, | |||
} | |||
// (no response) |
@@ -5,7 +5,7 @@ mod factory; | |||
pub use factory::{FactoryAPI, FactoryError}; | |||
mod factory_json; | |||
pub use factory_json::{ErrorPayload, SearchPayload, SearchResponse, SearchResponseItem, RobotInfo, RobotPrice, CreateRobotPayload, CreateRobotResponse, FactoryInfoResponse, PublishRobotPayload, PublishRobotResponse, MyRobotsResponse, GetRobotResponse}; | |||
pub use factory_json::{ErrorPayload, SearchPayload, SearchResponse, SearchResponseItem, RobotInfo, RobotPrice, CreateRobotPayload, CreateRobotResponse, FactoryInfoResponse, PublishRobotPayload, PublishRobotResponse, MyRobotsResponse, GetRobotResponse, ModerateRobotPayload, ReportRobotPayload}; | |||
mod portal; | |||
pub use self::portal::{PortalTokenProvider, AccountInfo, PortalCheckResponse, ITokenProvider}; |
@@ -0,0 +1,219 @@ | |||
#[cfg(feature = "robocraft2")] | |||
use libfj::robocraft2; | |||
#[cfg(feature = "robocraft2")] | |||
async fn builder() -> robocraft2::FactoryAPI { | |||
let token = robocraft2::PortalTokenProvider::with_username("FJAPIC00L", "P4$$w0rd").await.unwrap(); | |||
robocraft2::FactoryAPI::with_auth(Box::new(token)) | |||
} | |||
#[cfg(feature = "robocraft2")] | |||
//#[tokio::test] | |||
#[allow(dead_code)] | |||
async fn robocraft2_factory_moderate() -> Result<(), ()> { | |||
let api = builder().await; | |||
let robot = api.list().await.unwrap().results.pop().unwrap(); | |||
let result = api.moderate(robocraft2::ModerateRobotPayload { | |||
approve: false, | |||
reason: "Automated test".to_owned(), | |||
}, robot.robot.id).await; | |||
assert!(result.is_ok()); | |||
Ok(()) | |||
} | |||
#[cfg(feature = "robocraft2")] | |||
//#[tokio::test] | |||
#[allow(dead_code)] | |||
async fn robocraft2_factory_report() -> Result<(), ()> { | |||
let api = builder().await; | |||
let robot = api.list().await.unwrap().results.pop().unwrap(); | |||
let result = api.report(robocraft2::ReportRobotPayload { | |||
reason: "Automated test".to_owned(), | |||
}, robot.robot.id).await; | |||
assert!(result.is_ok()); | |||
Ok(()) | |||
} | |||
#[cfg(feature = "robocraft2")] | |||
//#[tokio::test] | |||
#[allow(dead_code)] | |||
async fn robocraft2_factory_default_query() -> Result<(), ()> { | |||
let api = builder().await; | |||
let result = api.list().await; | |||
assert!(result.is_ok()); | |||
let robo_info = unwrap_factory2(result); | |||
assert_ne!(robo_info.results.len(), 0); | |||
for robot in &robo_info.results { | |||
assert_ne!(robot.robot.name, ""); | |||
assert_ne!(robot.robot.creator_id, ""); | |||
assert_ne!(robot.robot.creator_id, ""); | |||
assert_ne!(robot.robot.image, ""); | |||
//println!("RobotInfo.to_string() -> `{}`", robot.robot.to_string()); | |||
println!("SearchResponseItem {}", serde_json::to_string_pretty(&robot).unwrap()); | |||
} | |||
Ok(()) | |||
} | |||
#[cfg(feature = "robocraft2")] | |||
#[tokio::test] | |||
async fn robocraft2_factory_info() -> Result<(), ()> { | |||
let api = builder().await; | |||
let result = api.factory_info().await; | |||
assert!(result.is_ok()); | |||
let crf_info = unwrap_factory2(result); | |||
println!("FactoryInfo {:?}", crf_info); | |||
Ok(()) | |||
} | |||
#[cfg(feature = "robocraft2")] | |||
//#[tokio::test] | |||
#[allow(dead_code)] | |||
async fn robocraft2_factory_upload() -> Result<(), ()> { | |||
let api = builder().await; | |||
// copy default bot | |||
let result = api.get("08dab2c9-7a72-4ec4-843c-154fe8768e91".to_owned()).await; | |||
assert!(result.is_ok()); | |||
let robot = unwrap_factory2(result); | |||
let result = api.create_robot( | |||
robocraft2::CreateRobotPayload { | |||
name: "API is easy".to_owned(), | |||
data: robot.data, // base64 | |||
image: "".to_owned(), // base64 | |||
base_cpu: 42, | |||
weapon_cpu: 1, | |||
cosmetic_cpu: 6, | |||
cluster_count: 1, | |||
block_counts: vec![ | |||
(42, 3), | |||
(3, 6) | |||
].drain(..).collect(), | |||
materials_used: vec![ | |||
8, | |||
4 | |||
].drain(..).collect(), | |||
minimum_offset_x: 0.0, | |||
minimum_offset_y: 0.0, | |||
minimum_offset_z: 0.0, | |||
maximum_offset_x: 0.0, | |||
maximum_offset_y: 0.0, | |||
maximum_offset_z: 0.0, | |||
} | |||
).await; | |||
//assert!(result.is_ok()); | |||
let robot_info = unwrap_factory2(result); | |||
println!("CreateRobotInfo {:?}", robot_info); | |||
let result = api.publish_robot( | |||
robocraft2::PublishRobotPayload { | |||
name: "CRF API oh my".to_owned(), | |||
description: "There once was a person named NGnius, who simply wasn't that bright.\nBut he had a misleading name, and wasn't not quite unhated\nSo he thought it alright to put up a fight\nand get banned for reverse engineering".to_owned(), | |||
techpoints: -42, | |||
bloxcoin: 123 | |||
}, robot_info.header.id.clone()).await; | |||
//assert!(result.is_ok()); | |||
let _publish_info = unwrap_factory2(result); | |||
// clean up | |||
let result = api.unpublish_bot(robot_info.header.id.clone()).await; | |||
//assert!(result.is_ok()); | |||
let _robot = unwrap_factory2(result); | |||
let result = api.delete_robot(robot_info.header.id).await; | |||
//assert!(result.is_ok()); | |||
let _robot = unwrap_factory2(result); | |||
Ok(()) | |||
} | |||
#[cfg(feature = "robocraft2")] | |||
#[tokio::test] | |||
async fn robocraft2_factory_my_bots() -> Result<(), ()> { | |||
let api = robocraft2::FactoryAPI::with_auth(Box::new(robocraft2::PortalTokenProvider::with_username("FJAPIC00L", "P4$$w0rd").await.unwrap())); | |||
let result = api.my_robots().await; | |||
assert!(result.is_ok()); | |||
let robo_info = unwrap_factory2(result); | |||
assert_ne!(robo_info.vehicles.len(), 0); | |||
for robot in &robo_info.vehicles { | |||
assert_ne!(robot.name, ""); | |||
assert_ne!(robot.creator_id, ""); | |||
assert_ne!(robot.creator_id, ""); | |||
assert_ne!(robot.image, ""); | |||
println!("My bot `{}`", robot.to_string()); | |||
//println!("my vehicle {}", serde_json::to_string_pretty(&robot).unwrap()); | |||
} | |||
Ok(()) | |||
} | |||
#[cfg(feature = "robocraft2")] | |||
#[tokio::test] | |||
async fn robocraft2_factory_my_published_bots() -> Result<(), ()> { | |||
let api = robocraft2::FactoryAPI::with_auth(Box::new(robocraft2::PortalTokenProvider::with_username("FJAPIC00L", "P4$$w0rd").await.unwrap())); | |||
let result = api.my_published_robots().await; | |||
assert!(result.is_ok()); | |||
let robo_info = unwrap_factory2(result); | |||
//assert_ne!(robo_info.vehicles.len(), 0); | |||
for robot in &robo_info.vehicles { | |||
assert_ne!(robot.name, ""); | |||
assert_ne!(robot.creator_id, ""); | |||
assert_ne!(robot.creator_id, ""); | |||
assert_ne!(robot.image, ""); | |||
println!("My pub bot `{}`", robot.to_string()); | |||
//println!("pub vehicle {}", serde_json::to_string_pretty(&robot).unwrap()); | |||
} | |||
Ok(()) | |||
} | |||
#[cfg(feature = "robocraft2")] | |||
//#[tokio::test] | |||
#[allow(dead_code)] | |||
async fn robocraft2_factory_bot() -> Result<(), ()> { | |||
let api = robocraft2::FactoryAPI::with_auth(Box::new(robocraft2::PortalTokenProvider::with_username("FJAPIC00L", "P4$$w0rd").await.unwrap())); | |||
let result = api.get("08dab2c9-7a72-4ec4-843c-154fe8768e91".to_owned()).await; | |||
//assert!(result.is_ok()); | |||
let robot = unwrap_factory2(result); | |||
assert_ne!(robot.header.name, ""); | |||
assert_ne!(robot.header.creator_id, ""); | |||
assert_ne!(robot.header.creator_id, ""); | |||
//assert_ne!(robot.header.image, ""); | |||
//assert_ne!(robot.description, ""); | |||
assert_ne!(robot.data, ""); | |||
println!("robot {}", serde_json::to_string_pretty(&robot).unwrap()); | |||
Ok(()) | |||
} | |||
#[cfg(feature = "robocraft2")] | |||
//#[tokio::test] | |||
#[allow(dead_code)] | |||
async fn robocraft2_factory_delete_all_my_bots() -> Result<(), ()> { | |||
let api = builder().await; | |||
let my_bots = api.my_published_robots().await.unwrap(); | |||
for bot in my_bots.vehicles { | |||
let result = api.delete_robot(bot.id).await; | |||
unwrap_factory2(result); | |||
} | |||
Ok(()) | |||
} | |||
#[cfg(feature = "robocraft2")] | |||
//#[tokio::test] | |||
#[allow(dead_code)] | |||
async fn robocraft2_factory_unpublish_all_my_bots() -> Result<(), ()> { | |||
let api = builder().await; | |||
let my_bots = api.my_published_robots().await.unwrap(); | |||
for bot in my_bots.vehicles { | |||
let result = api.unpublish_bot(bot.id).await; | |||
unwrap_factory2(result); | |||
} | |||
Ok(()) | |||
} | |||
fn unwrap_factory2<T>(result: Result<T, robocraft2::FactoryError>) -> T { | |||
match result { | |||
Ok(t) => t, | |||
Err(e) => { | |||
//println!("FactoryError: {}", e); | |||
panic!("CRF2 Error: {}", e); | |||
} | |||
} | |||
} |
@@ -1,6 +1,6 @@ | |||
#[cfg(feature = "robocraft")] | |||
use libfj::robocraft; | |||
#[cfg(feature = "robocraft")] | |||
#[cfg(feature = "robocraft2")] | |||
use libfj::robocraft2; | |||
#[cfg(feature = "robocraft")] | |||
use libfj::robocraft::ITokenProvider; | |||
@@ -49,9 +49,7 @@ async fn robocraft2_account() -> Result<(), ()> { | |||
Ok(()) | |||
} | |||
// this requires human-interaction so it's disabled by default | |||
#[cfg(feature = "robocraft2")] | |||
#[allow(dead_code)] | |||
#[tokio::test] | |||
async fn robocraft2_simple_account() -> Result<(), ()> { | |||
let token_maybe = robocraft2::PortalTokenProvider::with_username("FJAPIC00L", "P4$$w0rd").await; | |||
@@ -121,178 +121,3 @@ async fn robocraft_factory_robot_cubes() -> Result<(), ()> { | |||
assert_eq!(colour_str, bot_info.response.colour_data); | |||
Ok(()) | |||
} | |||
#[cfg(feature = "robocraft2")] | |||
//#[tokio::test] | |||
async fn robocraft2_factory_default_query() -> Result<(), ()> { | |||
let api = robocraft2::FactoryAPI::with_auth(Box::new(robocraft2::PortalTokenProvider::with_username("FJAPIC00L", "P4$$w0rd").await.unwrap())); | |||
let result = api.list().await; | |||
assert!(result.is_ok()); | |||
let robo_info = unwrap_factory2(result); | |||
assert_ne!(robo_info.results.len(), 0); | |||
for robot in &robo_info.results { | |||
assert_ne!(robot.robot.name, ""); | |||
assert_ne!(robot.robot.creator_id, ""); | |||
assert_ne!(robot.robot.creator_id, ""); | |||
assert_ne!(robot.robot.image, ""); | |||
//println!("RobotInfo.to_string() -> `{}`", robot.robot.to_string()); | |||
println!("SearchResponseItem {}", serde_json::to_string_pretty(&robot).unwrap()); | |||
} | |||
Ok(()) | |||
} | |||
#[cfg(feature = "robocraft2")] | |||
#[tokio::test] | |||
async fn robocraft2_factory_info() -> Result<(), ()> { | |||
let api = robocraft2::FactoryAPI::with_auth(Box::new(robocraft2::PortalTokenProvider::with_username("FJAPIC00L", "P4$$w0rd").await.unwrap())); | |||
let result = api.factory_info().await; | |||
assert!(result.is_ok()); | |||
let crf_info = unwrap_factory2(result); | |||
println!("FactoryInfo {:?}", crf_info); | |||
Ok(()) | |||
} | |||
#[cfg(feature = "robocraft2")] | |||
//#[tokio::test] | |||
async fn robocraft2_factory_upload() -> Result<(), ()> { | |||
let api = robocraft2::FactoryAPI::with_auth(Box::new(robocraft2::PortalTokenProvider::with_username("FJAPIC00L", "P4$$w0rd").await.unwrap())); | |||
// copy default bot | |||
let result = api.get("08dab2c9-7a72-4ec4-843c-154fe8768e91".to_owned()).await; | |||
assert!(result.is_ok()); | |||
let robot = unwrap_factory2(result); | |||
let result = api.create_robot( | |||
robocraft2::CreateRobotPayload { | |||
name: "API is easy".to_owned(), | |||
data: robot.data, // base64 | |||
image: "".to_owned(), // base64 | |||
base_cpu: 42, | |||
weapon_cpu: 1, | |||
cosmetic_cpu: 6, | |||
cluster_count: 1, | |||
block_counts: vec![ | |||
(42, 3), | |||
(3, 6) | |||
].drain(..).collect(), | |||
materials_used: vec![ | |||
8, | |||
4 | |||
].drain(..).collect(), | |||
minimum_offset_x: 0.0, | |||
minimum_offset_y: 0.0, | |||
minimum_offset_z: 0.0, | |||
maximum_offset_x: 0.0, | |||
maximum_offset_y: 0.0, | |||
maximum_offset_z: 0.0, | |||
} | |||
).await; | |||
//assert!(result.is_ok()); | |||
let robot_info = unwrap_factory2(result); | |||
println!("CreateRobotInfo {:?}", robot_info); | |||
let result = api.publish_robot( | |||
robocraft2::PublishRobotPayload { | |||
name: "CRF API oh my".to_owned(), | |||
description: "There once was a person named NGnius, who simply wasn't that bright.\nBut he had a misleading name, and wasn't not quite unhated\nSo he thought it alright to put up a fight\nand get banned for reverse engineering".to_owned(), | |||
techpoints: -42, | |||
bloxcoin: 123 | |||
}, robot_info.header.id.clone()).await; | |||
//assert!(result.is_ok()); | |||
let _publish_info = unwrap_factory2(result); | |||
// clean up | |||
let result = api.unpublish_bot(robot_info.header.id.clone()).await; | |||
//assert!(result.is_ok()); | |||
let _robot = unwrap_factory2(result); | |||
let result = api.delete_robot(robot_info.header.id).await; | |||
//assert!(result.is_ok()); | |||
let _robot = unwrap_factory2(result); | |||
Ok(()) | |||
} | |||
#[cfg(feature = "robocraft2")] | |||
#[tokio::test] | |||
async fn robocraft2_factory_my_bots() -> Result<(), ()> { | |||
let api = robocraft2::FactoryAPI::with_auth(Box::new(robocraft2::PortalTokenProvider::with_username("FJAPIC00L", "P4$$w0rd").await.unwrap())); | |||
let result = api.my_robots().await; | |||
assert!(result.is_ok()); | |||
let robo_info = unwrap_factory2(result); | |||
assert_ne!(robo_info.vehicles.len(), 0); | |||
for robot in &robo_info.vehicles { | |||
assert_ne!(robot.name, ""); | |||
assert_ne!(robot.creator_id, ""); | |||
assert_ne!(robot.creator_id, ""); | |||
assert_ne!(robot.image, ""); | |||
println!("My bot `{}`", robot.to_string()); | |||
//println!("my vehicle {}", serde_json::to_string_pretty(&robot).unwrap()); | |||
} | |||
Ok(()) | |||
} | |||
#[cfg(feature = "robocraft2")] | |||
#[tokio::test] | |||
async fn robocraft2_factory_my_published_bots() -> Result<(), ()> { | |||
let api = robocraft2::FactoryAPI::with_auth(Box::new(robocraft2::PortalTokenProvider::with_username("FJAPIC00L", "P4$$w0rd").await.unwrap())); | |||
let result = api.my_published_robots().await; | |||
assert!(result.is_ok()); | |||
let robo_info = unwrap_factory2(result); | |||
//assert_ne!(robo_info.vehicles.len(), 0); | |||
for robot in &robo_info.vehicles { | |||
assert_ne!(robot.name, ""); | |||
assert_ne!(robot.creator_id, ""); | |||
assert_ne!(robot.creator_id, ""); | |||
assert_ne!(robot.image, ""); | |||
println!("My pub bot `{}`", robot.to_string()); | |||
//println!("pub vehicle {}", serde_json::to_string_pretty(&robot).unwrap()); | |||
} | |||
Ok(()) | |||
} | |||
#[cfg(feature = "robocraft2")] | |||
//#[tokio::test] | |||
async fn robocraft2_factory_bot() -> Result<(), ()> { | |||
let api = robocraft2::FactoryAPI::with_auth(Box::new(robocraft2::PortalTokenProvider::with_username("FJAPIC00L", "P4$$w0rd").await.unwrap())); | |||
let result = api.get("08dab2c9-7a72-4ec4-843c-154fe8768e91".to_owned()).await; | |||
//assert!(result.is_ok()); | |||
let robot = unwrap_factory2(result); | |||
assert_ne!(robot.header.name, ""); | |||
assert_ne!(robot.header.creator_id, ""); | |||
assert_ne!(robot.header.creator_id, ""); | |||
//assert_ne!(robot.header.image, ""); | |||
//assert_ne!(robot.description, ""); | |||
assert_ne!(robot.data, ""); | |||
println!("robot {}", serde_json::to_string_pretty(&robot).unwrap()); | |||
Ok(()) | |||
} | |||
#[cfg(feature = "robocraft2")] | |||
//#[tokio::test] | |||
async fn robocraft2_factory_delete_bot() -> Result<(), ()> { | |||
let api = robocraft2::FactoryAPI::with_auth(Box::new(robocraft2::PortalTokenProvider::with_username("FJAPIC00L", "P4$$w0rd").await.unwrap())); | |||
let result = api.delete_robot("08dab2d2-dcae-4f52-8a77-bbce7cf10124".to_owned()).await; | |||
//assert!(result.is_ok()); | |||
let _robot = unwrap_factory2(result); | |||
Ok(()) | |||
} | |||
#[cfg(feature = "robocraft2")] | |||
//#[tokio::test] | |||
async fn robocraft2_factory_unpublish_bot() -> Result<(), ()> { | |||
let api = robocraft2::FactoryAPI::with_auth(Box::new(robocraft2::PortalTokenProvider::with_username("FJAPIC00L", "P4$$w0rd").await.unwrap())); | |||
let result = api.unpublish_bot("08dab2d3-2a68-48c6-8fd6-a59a663336ca".to_owned()).await; | |||
//assert!(result.is_ok()); | |||
let _robot = unwrap_factory2(result); | |||
Ok(()) | |||
} | |||
fn unwrap_factory2<T>(result: Result<T, robocraft2::FactoryError>) -> T { | |||
match result { | |||
Ok(t) => t, | |||
Err(e) => { | |||
//println!("FactoryError: {}", e); | |||
panic!("CRF2 Error: {}", e); | |||
} | |||
} | |||
} |