platz_chart_ext/actions/
v0.rs

1use crate::collection::UiSchemaCollections;
2use crate::error::UiSchemaInputError;
3use crate::ui_schema::UiSchema;
4use serde::{Deserialize, Serialize};
5use url::Url;
6use uuid::Uuid;
7
8#[derive(Clone, Debug, Deserialize, Serialize)]
9#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
10pub struct ChartExtActionsV0 {
11    pub schema_version: u64,
12    pub actions: Vec<ChartExtActionV0>,
13}
14
15impl ChartExtActionsV0 {
16    pub fn find(&self, action_id: &str) -> Option<&ChartExtActionV0> {
17        self.actions.iter().find(|action| action.id == action_id)
18    }
19
20    pub fn get_actions(&self) -> Vec<ChartExtActionV0> {
21        self.actions.to_vec()
22    }
23}
24
25#[derive(Clone, Debug, Copy, PartialEq, Eq, Serialize, Deserialize)]
26#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
27pub enum ChartExtActionUserDeploymentRole {
28    Owner,
29    Maintainer,
30}
31
32#[derive(Clone, Debug, Deserialize, Serialize)]
33#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
34pub enum ChartExtActionEndpoint {
35    #[serde(rename = "standard_ingress")]
36    StandardIngress,
37}
38
39#[derive(Clone, Debug, Deserialize, Serialize)]
40#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
41#[serde(rename_all = "UPPERCASE")]
42pub enum ChartExtActionMethod {
43    Get,
44    Post,
45    Put,
46    Patch,
47    Delete,
48}
49
50#[derive(Clone, Debug, Deserialize, Serialize)]
51#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
52pub struct ChartExtActionTarget {
53    pub endpoint: ChartExtActionEndpoint,
54    pub path: String,
55    pub method: ChartExtActionMethod,
56}
57
58impl ChartExtActionTarget {
59    pub async fn call<R, T, E>(&self, resolver: &R, body: T) -> Result<String, E>
60    where
61        R: ChartExtActionTargetResolver,
62        T: Serialize,
63        E: From<R::Error> + From<reqwest::Error>,
64    {
65        let url = resolver.resolve(self).await?;
66        let method = match self.method {
67            ChartExtActionMethod::Get => reqwest::Method::GET,
68            ChartExtActionMethod::Post => reqwest::Method::POST,
69            ChartExtActionMethod::Put => reqwest::Method::PUT,
70            ChartExtActionMethod::Patch => reqwest::Method::PATCH,
71            ChartExtActionMethod::Delete => reqwest::Method::DELETE,
72        };
73
74        Ok(reqwest::Client::new()
75            .request(method, url)
76            .json(&body)
77            .send()
78            .await?
79            .error_for_status()?
80            .text()
81            .await?)
82    }
83}
84
85pub trait ChartExtActionTargetResolver {
86    type Error;
87
88    #[allow(async_fn_in_trait)]
89    async fn resolve(&self, target: &ChartExtActionTarget) -> Result<Url, Self::Error>;
90}
91
92#[derive(Clone, Debug, Deserialize, Serialize)]
93#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
94pub struct ChartExtActionV0 {
95    pub id: String,
96    pub allowed_role: ChartExtActionUserDeploymentRole,
97    #[serde(default)]
98    pub allowed_on_statuses: Vec<String>,
99    #[serde(flatten)]
100    pub target: ChartExtActionTarget,
101    pub title: String,
102    pub fontawesome_icon: Option<String>,
103    pub description: String,
104    #[serde(default)]
105    pub dangerous: bool,
106    pub ui_schema: Option<UiSchema>,
107}
108
109impl ChartExtActionV0 {
110    pub async fn generate_body<C>(
111        &self,
112        env_id: Uuid,
113        inputs: serde_json::Value,
114    ) -> Result<serde_json::Value, UiSchemaInputError<C::Error>>
115    where
116        C: UiSchemaCollections,
117    {
118        let ui_schema = match self.ui_schema.as_ref() {
119            None => return Ok(inputs),
120            Some(ui_schema) => ui_schema,
121        };
122        Ok(ui_schema.get_values::<C>(env_id, &inputs).await?.into())
123    }
124}