clevercloud_sdk/v2/
plan.rs

1//! # Addon provider plan module
2//!
3//! This module provides helpers and structures to interact with the plan api of
4//! the addon providers
5
6#[cfg(feature = "logging")]
7use log::{Level, debug, log_enabled};
8use oauth10a::client::{ClientError, RestClient};
9
10use crate::{
11    Client,
12    v2::addon::{Plan, Provider},
13    v4::addon_provider::AddonProviderId,
14};
15
16// -----------------------------------------------------------------------------
17// Constants
18
19/// Config Provider addon have an unique and hard-coded plan as it is free to use
20pub const CONFIG_PROVIDER: &str = "plan_5d8e9596-dd73-4b73-84d9-e165372c5324";
21
22// -----------------------------------------------------------------------------
23// Error enumeration
24
25#[derive(thiserror::Error, Debug)]
26pub enum Error {
27    #[error("failed to fetch list of addon providers, {0}")]
28    List(ClientError),
29    #[error("failed to fetch details of addon provider '{0}'")]
30    Get(AddonProviderId),
31    #[error("failed to find plan '{0}' for addon provider '{1}' amongst available options: {2}")]
32    Plan(String, AddonProviderId, String),
33}
34
35// -----------------------------------------------------------------------------
36// Helpers method
37
38#[cfg_attr(feature = "tracing", tracing::instrument)]
39/// Returns the list of details relative to the addon providers.
40pub async fn list(client: &Client) -> Result<Vec<Provider>, Error> {
41    let path = format!("{}/v2/products/addonproviders", client.endpoint);
42
43    #[cfg(feature = "logging")]
44    if log_enabled!(Level::Debug) {
45        debug!("execute a request to list plans of the addon-provider, path: '{path}'");
46    }
47
48    client.get(&path).await.map_err(Error::List)
49}
50
51#[cfg_attr(feature = "tracing", tracing::instrument)]
52/// Returns the plan matching `pattern` for the given addon provider, if any.
53///
54/// # Errors
55///
56/// * [`Error::List`]: failed to fetch list of details relative to addon providers.
57/// * [`Error::Get`]: failed to fetch details of addon provider.
58/// * [`Error::Plan`]: failed to find plan.
59pub async fn find(
60    client: &Client,
61    addon_provider_id: &AddonProviderId,
62    pattern: &str,
63) -> Result<Option<Plan>, Error> {
64    let providers = list(client).await?;
65    let addon_provider_id_str = addon_provider_id.as_str();
66
67    // Find the provider matching the addon provider id
68    let provider = providers
69        .into_iter()
70        .find(|provider| provider.id == addon_provider_id_str)
71        .ok_or(Error::Get(addon_provider_id.to_owned()))?;
72
73    // It seems that some addon providers may validly not have plans
74    // NOTE: this is error prone, maybe we should set the field to `Option<Vec<Plan>>` instead
75    if provider.plans.is_empty() {
76        return Ok(None);
77    }
78
79    // Find the plan matching the pattern
80    if let Some(plan) = provider.plans.iter().find(|plan| {
81        plan.slug.eq_ignore_ascii_case(pattern)
82            || plan.name.eq_ignore_ascii_case(pattern)
83            || plan.id.eq_ignore_ascii_case(pattern)
84    }) {
85        return Ok(Some(plan.to_owned()));
86    }
87
88    // No match
89    Err(Error::Plan(
90        pattern.to_owned(),
91        addon_provider_id.to_owned(),
92        provider
93            .plans
94            .into_iter()
95            .map(|plan| format!("'{}' ('{}')", plan.name, plan.slug))
96            .collect::<Vec<_>>()
97            .join(", "),
98    ))
99}