use crate::client::CloudflareClient;
use crate::error::Result;
use serde::{Deserialize, Deserializer, Serialize};
fn deserialize_null_default<'de, D, T>(deserializer: D) -> std::result::Result<Vec<T>, D::Error>
where
D: Deserializer<'de>,
T: Deserialize<'de>,
{
let opt = Option::deserialize(deserializer)?;
Ok(opt.unwrap_or_default())
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Zone {
pub id: String,
pub name: String,
pub status: String,
pub paused: bool,
#[serde(rename = "type")]
pub zone_type: String,
pub development_mode: i32,
#[serde(default, deserialize_with = "deserialize_null_default")]
pub name_servers: Vec<String>,
#[serde(default, deserialize_with = "deserialize_null_default")]
pub original_name_servers: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub created_on: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub modified_on: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub activated_on: Option<String>,
}
#[derive(Clone)]
pub struct ZoneService {
client: CloudflareClient,
}
impl ZoneService {
pub(crate) fn new(client: CloudflareClient) -> Self {
Self { client }
}
pub fn list(&self) -> ListZonesRequest {
ListZonesRequest {
service: self.clone(),
name: None,
status: None,
page: None,
per_page: None,
}
}
pub async fn get(&self, zone_id: impl Into<String>) -> Result<Zone> {
let zone_id = zone_id.into();
let response = self.client.get(&format!("/zones/{}", zone_id)).await?;
CloudflareClient::handle_response(response).await
}
pub async fn find_by_name(&self, name: impl Into<String>) -> Result<Option<Zone>> {
let name = name.into();
let zones = self.list().name(&name).send().await?;
Ok(zones.into_iter().find(|z| z.name == name))
}
pub async fn get_zone_id(&self, name: impl Into<String>) -> Result<String> {
let name = name.into();
let zone = self
.find_by_name(&name)
.await?
.ok_or_else(|| crate::error::Error::NotFound(format!("Zone '{}' not found", name)))?;
Ok(zone.id)
}
}
pub struct ListZonesRequest {
service: ZoneService,
name: Option<String>,
status: Option<String>,
page: Option<u32>,
per_page: Option<u32>,
}
impl ListZonesRequest {
pub fn name(mut self, name: impl Into<String>) -> Self {
self.name = Some(name.into());
self
}
pub fn status(mut self, status: impl Into<String>) -> Self {
self.status = Some(status.into());
self
}
pub fn page(mut self, page: u32) -> Self {
self.page = Some(page);
self
}
pub fn per_page(mut self, per_page: u32) -> Self {
self.per_page = Some(per_page);
self
}
pub async fn send(self) -> Result<Vec<Zone>> {
let mut params = Vec::new();
if let Some(name) = self.name {
params.push(("name", name));
}
if let Some(status) = self.status {
params.push(("status", status));
}
if let Some(page) = self.page {
params.push(("page", page.to_string()));
}
if let Some(per_page) = self.per_page {
params.push(("per_page", per_page.to_string()));
}
let response = self
.service
.client
.get_with_params("/zones", ¶ms)
.await?;
CloudflareClient::handle_response(response).await
}
}