wikijs 0.2.1

API bindings, CLI client and FUSE filesystem for Wiki.js written in Rust.
Documentation
use graphql_client::reqwest::post_graphql_blocking as post_graphql;
use reqwest::blocking::Client;
use serde::{Deserialize, Serialize};
use thiserror::Error;

use crate::common::{
    classify_response_error, classify_response_status_error, Int,
    KnownErrorCodes, ResponseStatus, UnknownError,
};

#[derive(Clone, Error, Debug, PartialEq)]
pub enum NavigationError {
    #[error("Unknown response error code: {code}: {message}")]
    UnknownErrorCode { code: i64, message: String },
    #[error("Unknown response error: {message}")]
    UnknownErrorMessage { message: String },
    #[error("Unknown response error.")]
    UnknownError,
}

impl From<i64> for NavigationError {
    fn from(code: i64) -> Self {
        NavigationError::UnknownErrorCode {
            code,
            message: "Unknown error".to_string(),
        }
    }
}

impl UnknownError for NavigationError {
    fn unknown_error_code(code: i64, message: String) -> Self {
        NavigationError::UnknownErrorCode { code, message }
    }
    fn unknown_error_message(message: String) -> Self {
        NavigationError::UnknownErrorMessage { message }
    }
    fn unknown_error() -> Self {
        NavigationError::UnknownError
    }
}

impl KnownErrorCodes for NavigationError {
    fn known_error_codes() -> Vec<i64> {
        Vec::new()
    }

    fn is_known_error_code(_code: i64) -> bool {
        false
    }
}

#[derive(Clone, Deserialize, Serialize, Debug)]
pub enum NavigationMode {
    NONE,
    TREE,
    MIXED,
    STATIC,
}

#[derive(Clone, Deserialize, Debug)]
pub struct NavigationConfig {
    pub mode: NavigationMode,
}

#[derive(Clone, Deserialize, Debug)]
pub struct NavigationTree {
    pub locale: String,
    pub items: Vec<Option<NavigationTreeItem>>,
}

#[derive(Clone, Deserialize, Debug)]
pub struct NavigationTreeItem {
    pub id: String,
    pub kind: String,
    pub label: Option<String>,
    pub icon: Option<String>,
    #[serde(rename = "targetType")]
    pub target_type: Option<String>,
    pub target: Option<String>,
    #[serde(rename = "visibilityMode")]
    pub visibility_mode: Option<String>,
    #[serde(rename = "visibilityGroups")]
    pub visibility_groups: Option<Vec<Option<Int>>>,
}

#[derive(Clone, Serialize, Debug)]
pub struct NavigationTreeInput {
    pub locale: String,
    pub items: Vec<Option<NavigationItemInput>>,
}

#[derive(Clone, Serialize, Debug)]
pub struct NavigationItemInput {
    pub id: String,
    pub kind: String,
    pub label: Option<String>,
    pub icon: Option<String>,
    #[serde(rename = "targetType")]
    pub target_type: Option<String>,
    pub target: Option<String>,
    #[serde(rename = "visibilityMode")]
    pub visibility_mode: Option<String>,
    #[serde(rename = "visibilityGroups")]
    pub visibility_groups: Option<Vec<Option<Int>>>,
}

pub mod navigation_config_get {
    use super::*;

    pub struct NavigationConfigGet;

    pub const OPERATION_NAME: &str = "NavigationConfigGet";
    pub const QUERY : & str = "query NavigationConfigGet {\n  navigation {\n    config {\n      mode\n    }\n  }\n}\n" ;

    #[derive(Serialize)]
    pub struct Variables;

    #[derive(Deserialize)]
    pub struct ResponseData {
        pub navigation: Option<Navigation>,
    }

    #[derive(Deserialize)]
    pub struct Navigation {
        pub config: NavigationConfig,
    }

    impl graphql_client::GraphQLQuery for NavigationConfigGet {
        type Variables = Variables;
        type ResponseData = ResponseData;

        fn build_query(
            variables: Self::Variables,
        ) -> graphql_client::QueryBody<Self::Variables> {
            graphql_client::QueryBody {
                variables,
                query: QUERY,
                operation_name: OPERATION_NAME,
            }
        }
    }
}

pub fn navigation_config_get(
    client: &Client,
    url: &str,
) -> Result<NavigationConfig, NavigationError> {
    let variables = navigation_config_get::Variables {};
    let response = post_graphql::<navigation_config_get::NavigationConfigGet, _>(
        client, url, variables,
    );
    if response.is_err() {
        return Err(NavigationError::UnknownErrorMessage {
            message: response.err().unwrap().to_string(),
        });
    }
    let response_body = response.unwrap();
    if let Some(data) = response_body.data {
        if let Some(navigation) = data.navigation {
            return Ok(navigation.config);
        }
    }
    Err(classify_response_error::<NavigationError>(
        response_body.errors,
    ))
}

pub mod navigation_tree_get {
    use super::*;

    pub struct NavigationTreeGet;

    pub const OPERATION_NAME: &str = "NavigationTreeGet";
    pub const QUERY : & str = "query NavigationTreeGet {\n  navigation {\n    tree {\n      locale\n      items {\n        id\n        kind\n        label\n        icon\n        targetType\n        target\n        visibilityMode\n        visibilityGroups\n      }\n    }\n  }\n}\n" ;

    #[derive(Serialize)]
    pub struct Variables;

    #[derive(Deserialize)]
    pub struct ResponseData {
        pub navigation: Option<Navigation>,
    }

    #[derive(Deserialize)]
    pub struct Navigation {
        pub tree: Vec<Option<NavigationTree>>,
    }

    impl graphql_client::GraphQLQuery for NavigationTreeGet {
        type Variables = Variables;
        type ResponseData = ResponseData;

        fn build_query(
            variables: Self::Variables,
        ) -> graphql_client::QueryBody<Self::Variables> {
            graphql_client::QueryBody {
                variables,
                query: QUERY,
                operation_name: OPERATION_NAME,
            }
        }
    }
}

pub fn navigation_tree_get(
    client: &Client,
    url: &str,
) -> Result<Vec<NavigationTree>, NavigationError> {
    let variables = navigation_tree_get::Variables {};
    let response = post_graphql::<navigation_tree_get::NavigationTreeGet, _>(
        client, url, variables,
    );
    if response.is_err() {
        return Err(NavigationError::UnknownErrorMessage {
            message: response.err().unwrap().to_string(),
        });
    }
    let response_body = response.unwrap();
    if let Some(data) = response_body.data {
        if let Some(navigation) = data.navigation {
            return Ok(navigation.tree.into_iter().flatten().collect());
        }
    }
    Err(classify_response_error::<NavigationError>(
        response_body.errors,
    ))
}

pub mod navigation_config_update {
    use super::*;

    pub struct NavigationConfigUpdate;

    pub const OPERATION_NAME: &str = "NavigationConfigUpdate";
    pub const QUERY : & str = "mutation NavigationConfigUpdate (\n  $mode: NavigationMode!\n) { \n  navigation {\n    updateConfig(mode: $mode) {\n      responseResult {\n        succeeded\n        errorCode\n        slug\n        message\n      }\n    }\n  }\n}\n" ;

    #[derive(Serialize)]
    pub struct Variables {
        pub mode: NavigationMode,
    }

    impl Variables {}

    #[derive(Deserialize)]
    pub struct ResponseData {
        pub navigation: Option<Navigation>,
    }

    #[derive(Deserialize)]
    pub struct Navigation {
        #[serde(rename = "updateConfig")]
        pub update_config: Option<UpdateConfig>,
    }
    #[derive(Deserialize)]
    pub struct UpdateConfig {
        #[serde(rename = "responseResult")]
        pub response_result: Option<ResponseStatus>,
    }

    impl graphql_client::GraphQLQuery for NavigationConfigUpdate {
        type Variables = Variables;
        type ResponseData = ResponseData;

        fn build_query(
            variables: Self::Variables,
        ) -> graphql_client::QueryBody<Self::Variables> {
            graphql_client::QueryBody {
                variables,
                query: QUERY,
                operation_name: OPERATION_NAME,
            }
        }
    }
}

pub fn navigation_config_update(
    client: &Client,
    url: &str,
    mode: NavigationMode,
) -> Result<(), NavigationError> {
    let variables = navigation_config_update::Variables { mode };
    let response = post_graphql::<
        navigation_config_update::NavigationConfigUpdate,
        _,
    >(client, url, variables);
    if response.is_err() {
        return Err(NavigationError::UnknownErrorMessage {
            message: response.err().unwrap().to_string(),
        });
    }
    let response_body = response.unwrap();
    if let Some(data) = response_body.data {
        if let Some(navigation) = data.navigation {
            if let Some(update_config) = navigation.update_config {
                if let Some(response_result) = update_config.response_result {
                    if response_result.succeeded {
                        return Ok(());
                    } else {
                        return Err(classify_response_status_error::<
                            NavigationError,
                        >(response_result));
                    }
                }
            }
        }
    }
    Err(classify_response_error::<NavigationError>(
        response_body.errors,
    ))
}

pub mod navigation_tree_update {
    use super::*;

    pub struct NavigationTreeUpdate;

    pub const OPERATION_NAME: &str = "NavigationTreeUpdate";
    pub const QUERY : & str = "mutation NavigationTreeUpdate (\n  $tree: [NavigationTreeInput]!\n) { \n  navigation {\n    updateTree(tree: $tree) {\n      responseResult {\n        succeeded\n        errorCode\n        slug\n        message\n      }\n    }\n  }\n}\n" ;

    #[derive(Serialize)]
    pub struct Variables {
        pub tree: Vec<Option<NavigationTreeInput>>,
    }

    impl Variables {}

    #[derive(Deserialize)]
    pub struct ResponseData {
        pub navigation: Option<Navigation>,
    }

    #[derive(Deserialize)]
    pub struct Navigation {
        #[serde(rename = "updateTree")]
        pub update_tree: Option<UpdateTree>,
    }
    #[derive(Deserialize)]
    pub struct UpdateTree {
        #[serde(rename = "responseResult")]
        pub response_result: Option<ResponseStatus>,
    }

    impl graphql_client::GraphQLQuery for NavigationTreeUpdate {
        type Variables = Variables;
        type ResponseData = ResponseData;

        fn build_query(
            variables: Self::Variables,
        ) -> graphql_client::QueryBody<Self::Variables> {
            graphql_client::QueryBody {
                variables,
                query: QUERY,
                operation_name: OPERATION_NAME,
            }
        }
    }
}

pub fn navigation_tree_update(
    client: &Client,
    url: &str,
    tree: Vec<NavigationTreeInput>,
) -> Result<(), NavigationError> {
    let variables = navigation_tree_update::Variables {
        tree: tree.into_iter().map(Some).collect(),
    };
    let response = post_graphql::<
        navigation_tree_update::NavigationTreeUpdate,
        _,
    >(client, url, variables);
    if response.is_err() {
        return Err(NavigationError::UnknownErrorMessage {
            message: response.err().unwrap().to_string(),
        });
    }
    let response_body = response.unwrap();
    if let Some(data) = response_body.data {
        if let Some(navigation) = data.navigation {
            if let Some(update_tree) = navigation.update_tree {
                if let Some(response_result) = update_tree.response_result {
                    if response_result.succeeded {
                        return Ok(());
                    } else {
                        return Err(classify_response_status_error::<
                            NavigationError,
                        >(response_result));
                    }
                }
            }
        }
    }
    Err(classify_response_error::<NavigationError>(
        response_body.errors,
    ))
}