1use serde::{Deserialize, Serialize};
2use std::{collections::HashMap, fmt::Display};
3
4#[derive(Debug, Serialize, Deserialize, Clone)]
6pub struct ShortenResponse {
7 pub short_url: String,
9}
10
11#[derive(Debug, Serialize, Default, Clone)]
13pub struct ShortenRequest {
14 pub(crate) url: String,
15 #[serde(skip_serializing_if = "Option::is_none")]
16 pub(crate) alias: Option<String>,
17 #[serde(skip_serializing_if = "Option::is_none")]
18 pub(crate) password: Option<String>,
19 #[serde(rename = "max-clicks", skip_serializing_if = "Option::is_none")]
20 pub(crate) max_clicks: Option<u32>,
21 #[serde(rename = "block-bots", skip_serializing_if = "Option::is_none")]
22 pub(crate) block_bots: Option<bool>,
23}
24
25impl ShortenRequest {
26 pub fn new<U: Into<String>>(url: U) -> Self {
28 ShortenRequest {
29 url: url.into(),
30 ..Default::default()
31 }
32 }
33 pub fn alias<A: Into<String>>(mut self, alias: A) -> Self {
35 self.alias = Some(alias.into());
36 self
37 }
38 pub fn password<P: Into<String>>(mut self, password: P) -> Self {
40 self.password = Some(password.into());
41 self
42 }
43 pub fn max_clicks(mut self, max: u32) -> Self {
45 self.max_clicks = Some(max);
46 self
47 }
48 pub fn block_bots(mut self, flag: bool) -> Self {
50 self.block_bots = Some(flag);
51 self
52 }
53}
54
55#[derive(Debug, Serialize, Default, Clone)]
57pub struct EmojiRequest {
58 pub(crate) url: String,
59 #[serde(rename = "emojies", skip_serializing_if = "Option::is_none")]
60 pub(crate) emojies: Option<String>,
61 #[serde(skip_serializing_if = "Option::is_none")]
62 pub(crate) password: Option<String>,
63 #[serde(rename = "max-clicks", skip_serializing_if = "Option::is_none")]
64 pub(crate) max_clicks: Option<u32>,
65 #[serde(rename = "block-bots", skip_serializing_if = "Option::is_none")]
66 pub(crate) block_bots: Option<bool>,
67}
68
69impl EmojiRequest {
70 pub fn new<U: Into<String>>(url: U) -> Self {
72 EmojiRequest {
73 url: url.into(),
74 ..Default::default()
75 }
76 }
77 pub fn emojies<E: Into<String>>(mut self, seq: E) -> Self {
79 self.emojies = Some(seq.into());
80 self
81 }
82 pub fn password<P: Into<String>>(mut self, password: P) -> Self {
84 self.password = Some(password.into());
85 self
86 }
87 pub fn max_clicks(mut self, max: u32) -> Self {
89 self.max_clicks = Some(max);
90 self
91 }
92 pub fn block_bots(mut self, flag: bool) -> Self {
94 self.block_bots = Some(flag);
95 self
96 }
97}
98
99#[derive(Debug, Serialize, Deserialize, Clone)]
101pub struct EmojiResponse {
102 pub short_url: String,
104}
105
106#[derive(Debug, Serialize, Default, Clone)]
108pub struct StatsRequest {
109 #[serde(skip_serializing)]
110 pub(crate) short_code: String,
111 #[serde(skip_serializing_if = "Option::is_none")]
112 pub(crate) password: Option<String>,
113}
114
115impl StatsRequest {
116 pub fn new(short_code: &str) -> Self {
118 StatsRequest {
119 short_code: short_code.to_string(),
120 password: None,
121 }
122 }
123 pub fn password<P: Into<String>>(mut self, password: P) -> Self {
125 self.password = Some(password.into());
126 self
127 }
128}
129
130#[derive(Debug, Serialize, Deserialize, Clone)]
132pub struct StatsResponse {
133 pub short_code: String,
135 pub url: String,
137 #[serde(rename = "total-clicks")]
139 pub total_clicks: u32,
140 pub total_unique_clicks: u32,
142 #[serde(rename = "creation-date")]
144 pub creation_date: Option<String>,
145 pub expired: Option<bool>,
147 #[serde(rename = "last-click")]
149 pub last_click: Option<String>,
150 #[serde(rename = "last-click-browser")]
152 pub last_click_browser: Option<String>,
153 #[serde(rename = "last-click-os")]
155 pub last_click_os: Option<String>,
156 #[serde(rename = "max-clicks")]
158 pub max_clicks: Option<u32>,
159 pub password: Option<String>,
161 pub block_bots: Option<bool>,
163 pub bots: Option<HashMap<String, u32>>,
165 pub browser: Option<HashMap<String, u32>>,
167 pub country: Option<HashMap<String, u32>>,
169 pub counter: Option<HashMap<String, u32>>,
171 pub unique_browser: Option<HashMap<String, u32>>,
173 pub unique_country: Option<HashMap<String, u32>>,
175 pub unique_counter: Option<HashMap<String, u32>>,
177 pub unique_os_name: Option<HashMap<String, u32>>,
179 pub unique_referrer: Option<HashMap<String, u32>>,
181}
182
183#[derive(Debug, Deserialize, Clone)]
185pub enum ExportFormat {
186 JSON,
188 CSV,
190 XLSX,
192 XML,
194}
195
196impl Display for ExportFormat {
197 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
198 match self {
199 ExportFormat::JSON => write!(f, "json"),
200 ExportFormat::CSV => write!(f, "csv"),
201 ExportFormat::XLSX => write!(f, "xlsx"),
202 ExportFormat::XML => write!(f, "xml"),
203 }
204 }
205}
206
207#[derive(Debug, Serialize, Deserialize, Clone)]
209pub struct ExportRequest {
210 #[serde(skip_serializing)]
212 pub(crate) short_code: String,
213 #[serde(skip_serializing)]
214 pub(crate) export_format: ExportFormat,
215 #[serde(skip_serializing_if = "Option::is_none")]
216 pub(crate) password: Option<String>,
217}
218
219impl ExportRequest {
220 pub fn new<S: Into<String>>(short_code: S, export_format: ExportFormat) -> Self {
222 ExportRequest {
223 short_code: short_code.into(),
224 export_format,
225 password: None,
226 }
227 }
228
229 pub fn password<P: Into<String>>(mut self, password: P) -> Self {
231 self.password = Some(password.into());
232 self
233 }
234}
235
236#[derive(Debug, Clone)]
238pub struct ExportResponse {
239 pub(crate) data: Vec<u8>,
241}
242
243impl ExportResponse {
244 pub fn save_to_file(&self, path: &str) -> std::io::Result<()> {
246 use std::fs::File;
247 use std::io::Write;
248
249 let mut file = File::create(path)?;
250 file.write_all(&self.data)?;
251 Ok(())
252 }
253
254 pub fn data(&self) -> &[u8] {
256 &self.data
257 }
258}