platz-chart-ext 0.7.0

Platz Helm chart extensions
Documentation
use crate::collection::UiSchemaCollections;
use crate::error::UiSchemaInputError;
use crate::ui_schema::UiSchema;
use serde::{Deserialize, Serialize};
use url::Url;
use uuid::Uuid;

#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
pub struct ChartExtActionsV0 {
    pub schema_version: u64,
    pub actions: Vec<ChartExtActionV0>,
}

impl ChartExtActionsV0 {
    pub fn find(&self, action_id: &str) -> Option<&ChartExtActionV0> {
        self.actions.iter().find(|action| action.id == action_id)
    }

    pub fn get_actions(&self) -> Vec<ChartExtActionV0> {
        self.actions.to_vec()
    }
}

#[derive(Clone, Debug, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
pub enum ChartExtActionUserDeploymentRole {
    Owner,
    Maintainer,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
pub enum ChartExtActionEndpoint {
    #[serde(rename = "standard_ingress")]
    StandardIngress,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[serde(rename_all = "UPPERCASE")]
pub enum ChartExtActionMethod {
    Get,
    Post,
    Put,
    Patch,
    Delete,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
pub struct ChartExtActionTarget {
    pub endpoint: ChartExtActionEndpoint,
    pub path: String,
    pub method: ChartExtActionMethod,
}

impl ChartExtActionTarget {
    pub async fn call<R, T, E>(&self, resolver: &R, body: T) -> Result<String, E>
    where
        R: ChartExtActionTargetResolver,
        T: Serialize,
        E: From<R::Error> + From<reqwest::Error>,
    {
        let url = resolver.resolve(self).await?;
        let method = match self.method {
            ChartExtActionMethod::Get => reqwest::Method::GET,
            ChartExtActionMethod::Post => reqwest::Method::POST,
            ChartExtActionMethod::Put => reqwest::Method::PUT,
            ChartExtActionMethod::Patch => reqwest::Method::PATCH,
            ChartExtActionMethod::Delete => reqwest::Method::DELETE,
        };

        Ok(reqwest::Client::new()
            .request(method, url)
            .json(&body)
            .send()
            .await?
            .error_for_status()?
            .text()
            .await?)
    }
}

pub trait ChartExtActionTargetResolver {
    type Error;

    #[allow(async_fn_in_trait)]
    async fn resolve(&self, target: &ChartExtActionTarget) -> Result<Url, Self::Error>;
}

#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
pub struct ChartExtActionV0 {
    pub id: String,
    pub allowed_role: ChartExtActionUserDeploymentRole,
    #[serde(default)]
    pub allowed_on_statuses: Vec<String>,
    #[serde(flatten)]
    pub target: ChartExtActionTarget,
    pub title: String,
    pub fontawesome_icon: Option<String>,
    pub description: String,
    #[serde(default)]
    pub dangerous: bool,
    pub ui_schema: Option<UiSchema>,
}

impl ChartExtActionV0 {
    pub async fn generate_body<C>(
        &self,
        env_id: Uuid,
        inputs: serde_json::Value,
    ) -> Result<serde_json::Value, UiSchemaInputError<C::Error>>
    where
        C: UiSchemaCollections,
    {
        let ui_schema = match self.ui_schema.as_ref() {
            None => return Ok(inputs),
            Some(ui_schema) => ui_schema,
        };
        Ok(ui_schema.get_values::<C>(env_id, &inputs).await?.into())
    }
}