nextcloud-route-extractor 0.1.3

Extract routes from nextcloud apps
Documentation
use php_literal_parser::Value;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::fmt::{Debug, Display, Formatter};

#[derive(Default, Debug, Clone, Deserialize, Serialize, PartialEq)]
#[allow(dead_code)]
pub struct AppRoutes {
    #[serde(default)]
    pub routes: Vec<Route>,
    #[serde(default)]
    pub ocs: Vec<Route>,
}

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Default)]
#[allow(dead_code)]
pub struct Route {
    #[serde(default)]
    pub root: Option<String>,
    pub url: String,
    pub name: String,
    #[serde(default)]
    pub verb: Verb,
    #[serde(default)]
    pub requirements: HashMap<String, Value>,
    #[serde(default)]
    pub postfix: Option<String>,
    #[serde(default)]
    pub defaults: HashMap<String, Value>,
}

const ROOT_URL_APPS: &[&str] = &[
    "cloud_federation_api",
    "core",
    "files_sharing",
    "files",
    "profile",
    "settings",
    "spreed",
];

impl Route {
    pub fn frontpage_url(&self, app: &str) -> String {
        let custom_root = app == "core" || (self.root.is_some() && ROOT_URL_APPS.contains(&app));
        if custom_root {
            format!("{}{}", self.root.as_deref().unwrap_or_default(), self.url)
        } else {
            format!("/apps/{app}{}", self.url)
        }
    }

    pub fn ocs_url(&self, app: &str) -> String {
        let custom_root = app == "core" || self.root.is_some();
        if custom_root {
            format!("{}{}", self.root.as_deref().unwrap_or_default(), self.url)
        } else {
            format!("/apps/{app}{}", self.url)
        }
    }

    pub fn id(&self, app: &str) -> String {
        let (page, method) = self.name.split_once('#').unwrap_or_default();
        format!(
            "{app}.{page}.{method}{}",
            self.postfix.as_deref().unwrap_or_default()
        )
    }
}

#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "UPPERCASE")]
pub enum Verb {
    #[default]
    Get,
    Post,
    Put,
    Delete,
    Head,
    Options,
    Patch,
}

impl Verb {
    pub fn as_str(&self) -> &'static str {
        match self {
            Verb::Get => "GET",
            Verb::Post => "POST",
            Verb::Put => "PUT",
            Verb::Delete => "DELETE",
            Verb::Head => "HEAD",
            Verb::Options => "OPTIONS",
            Verb::Patch => "PATCH",
        }
    }
}

impl Display for Verb {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.as_str())
    }
}