use chrono::{DateTime, Utc};
use reqwest::Method;
use serde::Deserialize;
use crate::client::Client;
use crate::error::Error;
use crate::http::{RequestSpec, encode_segment};
pub struct Public {
pub(crate) client: Client,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)]
#[non_exhaustive]
pub enum Generation {
#[serde(rename = "v1")]
V1,
#[serde(rename = "v2")]
V2,
#[serde(other)]
Unknown,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)]
#[serde(rename_all = "lowercase")]
#[non_exhaustive]
pub enum PublicStatus {
Active,
Inactive,
Expired,
Blocked,
#[serde(other)]
Unknown,
}
#[derive(Debug, Clone, Deserialize)]
#[non_exhaustive]
pub struct PublicLinkFacts {
pub alias: String,
pub short_url: String,
#[serde(default)]
pub long_url: Option<String>,
#[serde(default)]
pub created_at: Option<DateTime<Utc>>,
pub status: PublicStatus,
#[serde(default)]
pub max_clicks: Option<u64>,
pub block_bots: bool,
pub password_protected: bool,
}
#[derive(Debug, Clone, Deserialize)]
#[non_exhaustive]
pub struct PublicStats {
pub generation: Generation,
pub link: PublicLinkFacts,
pub stats: serde_json::Map<String, serde_json::Value>,
}
#[derive(Debug, Clone, Deserialize)]
#[non_exhaustive]
pub struct PreviewDestination {
pub url: String,
pub domain: String,
pub path: String,
pub is_https: bool,
}
#[derive(Debug, Clone, Deserialize)]
#[non_exhaustive]
pub struct PreviewGeoDestination {
pub url: String,
pub domain: String,
pub path: String,
pub is_https: bool,
pub countries: Vec<String>,
}
#[derive(Debug, Clone, Deserialize)]
#[non_exhaustive]
pub struct Preview {
pub generation: Generation,
pub alias: String,
pub short_url: String,
pub status: PublicStatus,
#[serde(default)]
pub created_at: Option<String>,
pub password_protected: bool,
#[serde(default)]
pub destination: Option<PreviewDestination>,
#[serde(default)]
pub geo_destinations: Option<Vec<PreviewGeoDestination>>,
}
impl Public {
pub fn stats(&self, short_code: impl Into<String>) -> PublicStatsBuilder {
PublicStatsBuilder {
client: self.client.clone(),
short_code: short_code.into(),
password: None,
}
}
pub async fn preview(&self, short_code: &str) -> Result<Preview, Error> {
self.client
.transport
.execute(RequestSpec::new(
Method::GET,
format!("/api/v1/public/preview/{}", encode_segment(short_code)),
))
.await
}
}
#[must_use = "builders do nothing until .send() is awaited"]
pub struct PublicStatsBuilder {
client: Client,
short_code: String,
password: Option<String>,
}
impl PublicStatsBuilder {
pub fn password(mut self, password: impl Into<String>) -> Self {
self.password = Some(password.into());
self
}
pub async fn send(self) -> Result<PublicStats, Error> {
let path = format!("/api/v1/public/stats/{}", encode_segment(&self.short_code));
let spec = match self.password {
Some(password) => RequestSpec::new(Method::POST, path)
.json(&serde_json::json!({ "password": password }))?,
None => RequestSpec::new(Method::GET, path),
};
self.client.transport.execute(spec).await
}
}