any_type 0.5.0

A library for the Anytype API
Documentation
use crate::api::RequestFailure;
use crate::icons::Icon;
use crate::node;
use crate::properties::Property;
use crate::types::{Type, TypeLayout};
use serde_json::{Map, Value};

#[derive(Clone, Debug)]
pub struct Template {
    pub archived: bool,
    pub icon: Option<Icon>,
    pub id: String,
    pub layout: TypeLayout,
    pub name: String,
    pub object: String,
    pub properties: Vec<Property>,
    pub snippet: String,
    pub space_id: String,
    pub typeobj: Option<Type>,
}
impl Template {
    pub fn to_json(&self) -> Value {
        let mut values = Map::new();
        values.insert("archived".to_string(), Value::Bool(self.archived.clone()));
        let icon = Value::Null;
        if self.icon.is_some() {
            self.icon.clone().unwrap().to_json();
        }
        values.insert("icon".to_string(), icon);
        values.insert("id".to_string(), Value::String(self.id.clone()));
        values.insert("layout".to_string(), Value::String(self.layout.to_string()));
        values.insert("name".to_string(), Value::String(self.name.clone()));
        values.insert("object".to_string(), Value::String(self.object.clone()));
        let mut property_values: Vec<Value> = Vec::new();
        for p in self.properties.iter() {
            property_values.push(p.to_json());
        }
        values.insert("properties".to_string(), Value::Array(property_values));
        let mut typeobj = Value::Null;
        if self.typeobj.is_some() {
            typeobj = self.typeobj.clone().unwrap().to_json();
        }
        values.insert("type".to_string(), typeobj);
        Value::Object(values)
    }
    /// Known Bug : GetTemplate can return a null if no template id is provided!
    pub(crate) fn from_json(json: Value) -> Self {
        let archived = json["archived"].as_bool().unwrap();
        let icon = Icon::from_json(json["icon"].clone());
        let id = json["id"].as_str().unwrap().to_string();
        let layout = TypeLayout::from_str(&json["layout"].as_str().unwrap().to_string());
        let name = json["name"].as_str().unwrap().to_string();
        let object = json["object"].as_str().unwrap().to_string();
        let properties: Vec<Property> = Vec::new();
        let snippet = json["snippet"].as_str().unwrap().to_string();
        let space_id = json["space_id"].as_str().unwrap().to_string();
        let typeobj = None;
        Template {
            archived,
            icon,
            id,
            layout,
            name,
            object,
            properties,
            snippet,
            space_id,
            typeobj,
        }
    }
    pub(crate) async fn from_response(response: reqwest::Response) -> Self {
        let json_input = response.text().await.unwrap();
        let json: serde_json::Value = serde_json::from_str(json_input.as_ref()).unwrap();
        let t = json["template"].clone();
        Template::from_json(t)
    }
}

#[derive(Debug)]
pub struct ListOfTemplates {
    pub templates: Vec<Template>,
    pub has_more: bool,
    pub next_offset: usize,
    pub offset: usize,
    pub limit: usize,
    pub total: usize,
}

#[derive(Debug)]
pub struct GetTemplateRequest<'a> {
    api_key: &'a str,
    server: &'a str,
    space_id: &'a str,
    type_id: &'a str,
    template_id: &'a str,
}
impl<'a> GetTemplateRequest<'a> {
    pub fn new(api_key: &'a str, server: &'a str) -> Self {
        GetTemplateRequest {
            api_key,
            server,
            space_id: "",
            type_id: "",
            template_id: "",
        }
    }
    pub fn template_id(mut self, template_id: &'a str) -> Self {
        self.template_id = template_id;
        self
    }
    pub fn space_id(mut self, space_id: &'a str) -> Self {
        self.space_id = space_id;
        self
    }
    pub fn type_id(mut self, type_id: &'a str) -> Self {
        self.type_id = type_id;
        self
    }
    pub async fn send(&self) -> Result<Template, RequestFailure> {
        let endpoint = format!(
            "/v1/spaces/{}/types/{}/templates/{}",
            self.space_id, self.type_id, self.template_id
        );
        match node::get(self.api_key, self.server, &endpoint).await {
            Ok(response) => {
                if response.status() == http::StatusCode::OK {
                    return Ok(Template::from_response(response).await);
                } else {
                    let possible_status: Vec<http::StatusCode> = Vec::from([
                        http::StatusCode::UNAUTHORIZED,
                        http::StatusCode::NOT_FOUND,
                        http::StatusCode::GONE,
                        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 ListTemplatesRequest<'a> {
    api_key: &'a str,
    server: &'a str,
    offset: u32,
    limit: u32,
    space_id: &'a str,
    type_id: &'a str,
}
impl<'a> ListTemplatesRequest<'a> {
    pub fn new(api_key: &'a str, server: &'a str) -> Self {
        ListTemplatesRequest {
            api_key,
            server,
            offset: 0,
            limit: 100,
            space_id: "",
            type_id: "",
        }
    }
    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 fn space_id(mut self, space_id: &'a str) -> Self {
        self.space_id = space_id;
        self
    }
    pub fn type_id(mut self, type_id: &'a str) -> Self {
        self.type_id = type_id;
        self
    }
    pub async fn send(&self) -> Result<ListOfTemplates, RequestFailure> {
        let endpoint = format!(
            "/v1/spaces/{}/types/{}/templates?offset={}&limit={}",
            self.space_id, self.type_id, self.offset, self.limit
        );
        match node::get(self.api_key, self.server, &endpoint).await {
            Ok(response) => {
                if response.status() == http::StatusCode::OK {
                    return Ok(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) -> ListOfTemplates {
        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<Template> = Vec::new();
        for t in 0..received.len() {
            let template_obj = Template::from_json(received[t].clone());
            data.push(template_obj);
        }
        let has_more: bool = json["pagination"]["has_more"].as_bool().unwrap();
        let total = json["pagination"]["total"].as_u64().unwrap() as usize;
        let offset = json["pagination"]["offset"].as_u64().unwrap() as usize;
        let limit = json["pagination"]["limit"].as_u64().unwrap() as usize;
        let next_offset = (offset as usize) + received.len();

        ListOfTemplates {
            templates: data,
            has_more,
            next_offset,
            offset,
            limit,
            total,
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    pub fn test_list_templates_request() {
        let request = ListTemplatesRequest::new("secret_api_key", "server_url")
            .limit(42)
            .offset(0)
            .space_id("lost_in_space")
            .type_id("id_of_type");
        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("space_id: \"lost_in_space"));
        assert!(internals.contains("type_id: \"id_of_type"));
        assert!(internals.contains("server: \"server_url\""));
        println!("{}", internals);
    }
}