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, Boolean,
    KnownErrorCodes, ResponseStatus, UnknownError,
};

#[derive(Clone, Error, Debug, PartialEq)]
pub enum ThemeError {
    #[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 ThemeError {
    fn from(code: i64) -> Self {
        ThemeError::UnknownErrorCode {
            code,
            message: "Unknown error".to_string(),
        }
    }
}

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

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

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

#[derive(Clone, Deserialize, Debug)]
pub struct Theme {
    pub key: Option<String>,
    pub title: Option<String>,
    pub author: Option<String>,
}

#[derive(Clone, Deserialize)]
pub struct ThemingConfig {
    pub theme: String,
    pub iconset: String,
    #[serde(rename = "darkMode")]
    pub dark_mode: Boolean,
    #[serde(rename = "tocPosition")]
    pub toc_position: Option<String>,
    #[serde(rename = "injectCSS")]
    pub inject_css: Option<String>,
    #[serde(rename = "injectHead")]
    pub inject_head: Option<String>,
    #[serde(rename = "injectBody")]
    pub inject_body: Option<String>,
}

pub mod theme_list {
    use super::*;

    pub struct ThemeList;

    pub const OPERATION_NAME: &str = "ThemeList";
    pub const QUERY : & str = "query ThemeList {\n  theming {\n    themes {\n      key\n      title\n      author\n    }\n  }\n}\n" ;

    #[derive(Serialize)]
    pub struct Variables;

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

    #[derive(Deserialize)]
    pub struct Theming {
        pub themes: Option<Vec<Option<Theme>>>,
    }

    impl graphql_client::GraphQLQuery for ThemeList {
        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 theme_list(
    client: &Client,
    url: &str,
) -> Result<Vec<Theme>, ThemeError> {
    let variables = theme_list::Variables {};
    let response =
        post_graphql::<theme_list::ThemeList, _>(client, url, variables);
    if response.is_err() {
        return Err(ThemeError::UnknownErrorMessage {
            message: response.err().unwrap().to_string(),
        });
    }
    let response_body = response.unwrap();
    if let Some(data) = response_body.data {
        if let Some(theming) = data.theming {
            if let Some(themes) = theming.themes {
                return Ok(themes.into_iter().flatten().collect());
            }
        }
    }
    Err(classify_response_error(response_body.errors))
}

pub mod theme_config_get {
    use super::*;

    pub struct ThemeConfigGet;

    pub const OPERATION_NAME: &str = "ThemeConfigGet";
    pub const QUERY : & str = "query ThemeConfigGet {\n  theming {\n    config {\n      theme\n      iconset\n      darkMode\n      tocPosition\n      injectCSS\n      injectHead\n      injectBody\n    }\n  }\n}\n" ;

    #[derive(Serialize)]
    pub struct Variables;

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

    #[derive(Deserialize)]
    pub struct Theming {
        pub config: Option<ThemingConfig>,
    }

    impl graphql_client::GraphQLQuery for ThemeConfigGet {
        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 theme_config_get(
    client: &Client,
    url: &str,
) -> Result<ThemingConfig, ThemeError> {
    let variables = theme_config_get::Variables {};
    let response = post_graphql::<theme_config_get::ThemeConfigGet, _>(
        client, url, variables,
    );
    if response.is_err() {
        return Err(ThemeError::UnknownErrorMessage {
            message: response.err().unwrap().to_string(),
        });
    }
    let response_body = response.unwrap();
    if let Some(data) = response_body.data {
        if let Some(theming) = data.theming {
            if let Some(config) = theming.config {
                return Ok(config);
            }
        }
    }
    Err(classify_response_error(response_body.errors))
}

pub mod theme_config_update {
    use super::*;

    pub struct ThemeConfigUpdate;

    pub const OPERATION_NAME: &str = "ThemeConfigUpdate";
    pub const QUERY : & str = "mutation ThemeConfigUpdate (\n  $theme: String!\n  $iconset: String!\n  $darkMode: Boolean!\n  $tocPosition: String\n  $injectCSS: String\n  $injectHead: String\n  $injectBody: String\n) {\n  theming {\n    setConfig (\n      theme: $theme\n      iconset: $iconset\n      darkMode: $darkMode\n      tocPosition: $tocPosition\n      injectCSS: $injectCSS\n      injectHead: $injectHead\n      injectBody: $injectBody\n    ) {\n      responseResult {\n        succeeded\n        errorCode\n        slug\n        message\n      }\n    }\n  }\n}\n" ;

    #[derive(Serialize)]
    pub struct Variables {
        pub theme: String,
        pub iconset: String,
        #[serde(rename = "darkMode")]
        pub dark_mode: Boolean,
        #[serde(rename = "tocPosition")]
        pub toc_position: Option<String>,
        #[serde(rename = "injectCSS")]
        pub inject_css: Option<String>,
        #[serde(rename = "injectHead")]
        pub inject_head: Option<String>,
        #[serde(rename = "injectBody")]
        pub inject_body: Option<String>,
    }

    impl Variables {}

    #[derive(Deserialize)]
    pub struct ResponseData {
        pub theming: Option<Theming>,
    }
    #[derive(Deserialize)]
    pub struct Theming {
        #[serde(rename = "setConfig")]
        pub set_config: Option<SetConfig>,
    }

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

    impl graphql_client::GraphQLQuery for ThemeConfigUpdate {
        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,
            }
        }
    }
}

#[allow(clippy::too_many_arguments)]
pub fn theme_config_update(
    client: &Client,
    url: &str,
    theme: String,
    iconset: String,
    dark_mode: Boolean,
    toc_position: Option<String>,
    inject_css: Option<String>,
    inject_head: Option<String>,
    inject_body: Option<String>,
) -> Result<(), ThemeError> {
    let variables = theme_config_update::Variables {
        theme,
        iconset,
        dark_mode,
        toc_position,
        inject_css,
        inject_head,
        inject_body,
    };
    let response = post_graphql::<theme_config_update::ThemeConfigUpdate, _>(
        client, url, variables,
    );
    if response.is_err() {
        return Err(ThemeError::UnknownErrorMessage {
            message: response.err().unwrap().to_string(),
        });
    }
    let response_body = response.unwrap();
    if let Some(data) = response_body.data {
        if let Some(theming) = data.theming {
            if let Some(set_config) = theming.set_config {
                if let Some(response_result) = set_config.response_result {
                    if response_result.succeeded {
                        return Ok(());
                    } else {
                        return Err(classify_response_status_error(
                            response_result,
                        ));
                    }
                }
            }
        }
    }
    Err(classify_response_error(response_body.errors))
}