use super::utils::{de_option_empty_string_as_none, parse_json_response};
use super::{Client, Error, OPENAPI_STYLE, OPENAPI_VERSION};
use bon::Builder;
use serde::{Deserialize, Serialize, Serializer};
use std::collections::HashMap;
use time::OffsetDateTime;
use u_sdk_common::helper::into_header_map;
use u_sdk_common::open_api_sign::{SignParams, get_openapi_request_header};
#[serde_with::skip_serializing_none]
#[derive(Builder, Serialize)]
#[serde(rename_all = "PascalCase")]
pub struct ListSites<'a> {
#[builder(start_fn)]
#[serde(skip_serializing)]
pub(crate) client: &'a Client,
#[builder(field)]
#[serde(
skip_serializing_if = "Vec::is_empty",
serialize_with = "serialize_tag_filter_as_json_string"
)]
tag_filter: Vec<(Option<&'a str>, Option<&'a str>)>,
site_name: Option<&'a str>,
site_search_type: Option<SiteSearchType>,
page_number: Option<i32>,
page_size: Option<i32>,
resource_group_id: Option<&'a str>,
status: Option<&'a str>,
only_enterprise: Option<bool>,
plan_subscribe_type: Option<PlanSubscribeType>,
coverage: Option<Coverage>,
access_type: Option<AccessType>,
order_by: Option<OrderBy>,
}
impl<'a, S: list_sites_builder::State> ListSitesBuilder<'a, S> {
pub fn tag_filter(mut self, item: (Option<&'a str>, Option<&'a str>)) -> Self {
self.tag_filter.push(item);
self
}
pub fn tag_filters(
mut self,
items: impl IntoIterator<Item = (Option<&'a str>, Option<&'a str>)>,
) -> Self {
self.tag_filter.extend(items);
self
}
}
#[serde_with::skip_serializing_none]
#[derive(Serialize)]
#[serde(rename_all = "PascalCase")]
struct TagFilterItem<'a> {
key: Option<&'a str>,
value: Option<&'a str>,
}
pub fn serialize_tag_filter_as_json_string<'a, S>(
tag_filter: &Vec<(Option<&'a str>, Option<&'a str>)>,
serializer: S,
) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let items: Vec<TagFilterItem<'a>> = tag_filter
.iter()
.filter(|(k, v)| k.is_some() || v.is_some())
.map(|(k, v)| TagFilterItem { key: *k, value: *v })
.collect();
let json = serde_json::to_string(&items).map_err(serde::ser::Error::custom)?;
serializer.serialize_str(&json)
}
#[derive(Serialize, Clone)]
#[serde(rename_all = "lowercase")]
pub enum SiteSearchType {
Prefix,
Suffix,
Exact,
Fuzzy,
}
#[derive(Serialize, Clone)]
pub enum PlanSubscribeType {
#[serde(rename = "basicplan")]
Basic,
#[serde(rename = "standardplan")]
Standard,
#[serde(rename = "advancedplan")]
Advanced,
#[serde(rename = "enterpriseplan")]
Enterprise,
}
#[derive(Serialize, Clone, Debug, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Coverage {
Domestic,
Global,
Overseas,
}
#[derive(Serialize, Clone, Debug, Deserialize)]
#[serde(rename_all = "UPPERCASE")]
pub enum AccessType {
NS,
CName,
}
#[derive(Serialize, Clone)]
#[serde(rename_all = "camelCase")]
pub enum OrderBy {
GmtCreate,
VisitTime,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct ListSitesResponse {
pub request_id: String,
pub page_number: i32,
pub page_size: i32,
pub total_count: i32,
pub sites: Vec<SiteInfo>,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct SiteInfo {
pub access_type: AccessType,
pub cname_zone: String,
pub coverage: Coverage,
#[serde(with = "time::serde::iso8601")]
pub create_time: OffsetDateTime,
#[serde(with = "time::serde::iso8601")]
pub update_time: OffsetDateTime,
pub instance_id: String,
pub name_server_list: String,
pub plan_name: String,
pub plan_spec_name: Option<String>,
pub resource_group_id: String,
pub site_id: i64,
pub site_name: String,
pub status: SiteStatus,
pub tags: Option<HashMap<String, String>>,
pub verify_code: String,
#[serde(with = "time::serde::iso8601")]
pub visit_time: OffsetDateTime,
#[serde(deserialize_with = "de_option_empty_string_as_none")]
pub offline_reason: Option<OfflineReason>,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum SiteStatus {
Pending,
Active,
Offline,
Moved,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum OfflineReason {
ExpirationArrears,
InternallyDisabled,
MissingIcp,
ContentViolation,
ProactivelyDisabled,
}
impl Client {
pub fn list_sites(&self) -> ListSitesBuilder<'_> {
ListSites::builder(self)
}
}
impl ListSites<'_> {
pub async fn send(&self) -> Result<ListSitesResponse, Error> {
let client = self.client;
let creds = client.credentials_provider.load().await?;
let sign_params = SignParams {
req_method: "GET",
host: &client.host,
query_map: self,
x_acs_action: "ListSites",
x_acs_version: OPENAPI_VERSION,
x_acs_security_token: creds.sts_security_token.as_deref(),
request_body: None,
style: &OPENAPI_STYLE,
};
let (common_headers, url_) =
get_openapi_request_header(&creds.access_key_secret, &creds.access_key_id, sign_params)
.map_err(|e| {
Error::Common(format!("failed to get openapi request header: {}", e))
})?;
let header_map = into_header_map(common_headers);
let resp = client
.http_client
.get(url_)
.headers(header_map)
.send()
.await?;
let data = parse_json_response(resp).await?;
Ok(data)
}
}