use crate::api::RequestFailure;
use crate::icons::Icon;
use crate::node;
use serde_json::{Value, json};
#[derive(Debug)]
pub struct Space {
pub description: String,
pub icon: Option<Icon>,
pub gateway_url: String,
pub id: String,
pub name: String,
pub network_id: String,
pub object: String,
}
impl Space {
pub(crate) fn from_json(json: Value) -> Self {
let description = json["description"].as_str().unwrap().to_string();
let gateway_url = json["gateway_url"].as_str().unwrap().to_string();
let icon = Icon::from_json(json["icon"].clone());
let id = json["id"].as_str().unwrap().to_string();
let name = json["name"].as_str().unwrap().to_string();
let network_id = json["network_id"].as_str().unwrap().to_string();
let object = json["object"].as_str().unwrap().to_string();
Space {
description,
icon,
gateway_url,
id,
name,
network_id,
object,
}
}
pub(crate) async fn from_response(response: reqwest::Response) -> Space {
let json_input = response.text().await.unwrap();
let json: serde_json::Value = serde_json::from_str(json_input.as_ref()).unwrap();
let o = json["space"].clone();
Space::from_json(o)
}
}
#[derive(Debug)]
pub struct ListOfSpaces {
pub spaces: Vec<Space>,
pub has_more: bool,
pub next_offset: u32,
pub offset: u32,
pub limit: u32,
pub total: u32,
}
#[derive(Debug)]
pub struct CreateSpaceRequest<'a> {
api_key: &'a str,
server: &'a str,
description: &'a str,
name: &'a str,
}
impl<'a> CreateSpaceRequest<'a> {
pub fn new(api_key: &'a str, server: &'a str) -> Self {
CreateSpaceRequest {
api_key,
description: "",
name: "",
server,
}
}
pub fn description(mut self, description: &'a str) -> Self {
self.description = description;
self
}
pub fn name(mut self, name: &'a str) -> Self {
self.name = name;
self
}
pub async fn send(&self) -> Result<Space, RequestFailure> {
let endpoint = "/v1/spaces".to_string();
let body = json!({
"description": self.description,
"name": self.name
})
.to_string();
match node::post(self.api_key, self.server, &endpoint, &body).await {
Ok(response) => {
if response.status() == http::StatusCode::CREATED {
return Ok(Space::from_response(response).await);
} else {
let possible_status: Vec<http::StatusCode> = Vec::from([
http::StatusCode::UNAUTHORIZED,
http::StatusCode::BAD_REQUEST,
http::StatusCode::TOO_MANY_REQUESTS,
http::StatusCode::INTERNAL_SERVER_ERROR,
]);
return Err(RequestFailure::api_error(response, possible_status).await);
}
}
Err(e) => Err(RequestFailure::reqwest_error(e)),
}
}
}
#[derive(Debug)]
pub struct GetSpaceRequest<'a> {
api_key: &'a str,
server: &'a str,
space_id: &'a str,
}
impl<'a> GetSpaceRequest<'a> {
pub fn new(api_key: &'a str, server: &'a str) -> Self {
GetSpaceRequest {
api_key,
server,
space_id: "",
}
}
pub fn space_id(mut self, space_id: &'a str) -> Self {
self.space_id = space_id;
self
}
pub async fn send(&self) -> Result<Space, RequestFailure> {
let endpoint = format!("/v1/spaces/{}", self.space_id);
match node::get(self.api_key, self.server, &endpoint).await {
Ok(response) => {
if response.status() == http::StatusCode::OK {
return Ok(Space::from_response(response).await);
} else {
let possible_status: Vec<http::StatusCode> = Vec::from([
http::StatusCode::UNAUTHORIZED,
http::StatusCode::INTERNAL_SERVER_ERROR,
]);
return Err(RequestFailure::api_error(response, possible_status).await);
}
}
Err(e) => Err(RequestFailure::reqwest_error(e)),
}
}
}
#[derive(Debug)]
pub struct ListSpacesRequest<'a> {
api_key: &'a str,
offset: u32,
limit: u32,
server: &'a str,
}
impl<'a> ListSpacesRequest<'a> {
pub fn new(api_key: &'a str, server: &'a str) -> Self {
ListSpacesRequest {
api_key,
offset: 0,
limit: 100,
server,
}
}
pub fn offset(mut self, offset: u32) -> Self {
self.offset = offset;
self
}
pub fn limit(mut self, limit: u32) -> Self {
self.limit = limit;
self
}
pub async fn send(&self) -> Result<ListOfSpaces, RequestFailure> {
let endpoint = format!("/v1/spaces?offset={}&limit={}", self.offset, self.limit);
match node::get(self.api_key, self.server, &endpoint).await {
Ok(response) => {
if response.status() == http::StatusCode::OK {
return self.response_to_list(response).await;
} else {
let possible_status: Vec<http::StatusCode> = Vec::from([
http::StatusCode::UNAUTHORIZED,
http::StatusCode::INTERNAL_SERVER_ERROR,
]);
return Err(RequestFailure::api_error(response, possible_status).await);
}
}
Err(e) => Err(RequestFailure::reqwest_error(e)),
}
}
async fn response_to_list(
&self,
response: reqwest::Response,
) -> Result<ListOfSpaces, RequestFailure> {
let json_input = response.text().await.unwrap();
let json: serde_json::Value = serde_json::from_str(json_input.as_ref()).unwrap();
let received = json["data"].as_array().unwrap();
let mut data: Vec<Space> = Vec::new();
for s in 0..received.len() {
let space = Space::from_json(received[s].clone());
data.push(space);
}
let has_more: bool = json["pagination"]["has_more"].as_bool().unwrap();
let total = json["pagination"]["total"].as_u64().unwrap() as u32;
let offset = json["pagination"]["offset"].as_u64().unwrap() as u32;
let limit = json["pagination"]["limit"].as_u64().unwrap() as u32;
let next_offset = (offset as u32) + received.len() as u32;
Ok(ListOfSpaces {
spaces: data,
has_more,
next_offset,
offset,
limit,
total,
})
}
}
#[derive(Debug)]
pub struct UpdateSpaceRequest<'a> {
api_key: &'a str,
description: &'a str,
name: &'a str,
server: &'a str,
space_id: &'a str,
}
impl<'a> UpdateSpaceRequest<'a> {
pub fn new(api_key: &'a str, server: &'a str) -> Self {
UpdateSpaceRequest {
api_key,
description: "",
name: "",
server,
space_id: "",
}
}
pub fn space_id(mut self, space_id: &'a str) -> Self {
self.space_id = space_id;
self
}
pub fn description(mut self, description: &'a str) -> Self {
self.description = description;
self
}
pub fn name(mut self, name: &'a str) -> Self {
self.name = name;
self
}
pub async fn send(&self) -> Result<Space, RequestFailure> {
let endpoint = format!("/v1/spaces/{}", self.space_id);
let body = json!({
"description": self.description,
"name": self.name
})
.to_string();
match node::patch(self.api_key, self.server, &endpoint, &body).await {
Ok(response) => {
if response.status() == http::StatusCode::OK {
return Ok(Space::from_response(response).await);
} else {
let possible_status: Vec<http::StatusCode> = Vec::from([
http::StatusCode::UNAUTHORIZED,
http::StatusCode::BAD_REQUEST,
http::StatusCode::FORBIDDEN,
http::StatusCode::NOT_FOUND,
http::StatusCode::TOO_MANY_REQUESTS,
http::StatusCode::INTERNAL_SERVER_ERROR,
]);
return Err(RequestFailure::api_error(response, possible_status).await);
}
}
Err(e) => Err(RequestFailure::reqwest_error(e)),
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
pub fn test_create_spaces_request() {
let request = CreateSpaceRequest::new("secret_api_key", "server_url")
.description("This is a test space!")
.name("lost_in_space");
let internals = format!("{:#?}", request);
assert!(internals.contains("api_key: \"secret_api_key\""));
assert!(internals.contains("description: \"This is a test space!"));
assert!(internals.contains("name: \"lost_in_space"));
assert!(internals.contains("server: \"server_url\""));
println!("{}", internals);
}
#[test]
pub fn test_get_space_request() {
let request =
GetSpaceRequest::new("secret_api_key", "server_url").space_id("bye-bye-baby-42");
let internals = format!("{:#?}", request);
assert!(internals.contains("api_key: \"secret_api_key\""));
assert!(internals.contains("space_id: \"bye-bye-baby-42"));
assert!(internals.contains("server: \"server_url\""));
println!("{}", internals);
}
#[test]
pub fn test_list_spaces_request() {
let request = ListSpacesRequest::new("secret_api_key", "server_url")
.offset(0)
.limit(42);
let internals = format!("{:#?}", request);
assert!(internals.contains("api_key: \"secret_api_key\""));
assert!(internals.contains("offset: 0"));
assert!(internals.contains("limit: 42"));
assert!(internals.contains("server: \"server_url\""));
println!("{}", internals);
}
#[test]
pub fn test_update_spaces_request() {
let request = UpdateSpaceRequest::new("secret_api_key", "server_url")
.description("This is a test space!")
.name("lost_in_space")
.space_id("bye-bye-baby-42");
let internals = format!("{:#?}", request);
assert!(internals.contains("api_key: \"secret_api_key\""));
assert!(internals.contains("description: \"This is a test space!"));
assert!(internals.contains("name: \"lost_in_space"));
assert!(internals.contains("server: \"server_url\""));
assert!(internals.contains("space_id: \"bye-bye-baby-42"));
println!("{}", internals);
}
}