any_type 0.5.0

A library for the Anytype API
Documentation
use crate::api::RequestFailure;
use crate::icons::Icon;
use crate::node;
use serde_json::{Value, json};

#[derive(Debug)]
/// Holds information relating to a single space/channel
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)]
/// Holds information relating to all spaces/channels in the vault
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)]
/// A builder struct that can build and run an CreateSpace API request
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
    }
    // Executes the API call by sending it to the server defined in the vault
    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)]
/// A builder struct that can build and run a GetSpace API request
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)]
/// A builder struct that can build and run a ListSpaces API request
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)]
/// A builder struct that can build and run an UpdateSpace API request
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);
    }
}