1use crate::{FilesClient, PaginationInfo, Result};
7use serde::{Deserialize, Serialize};
8use serde_json::json;
9
10#[derive(Debug, Clone, Serialize, Deserialize)]
12#[serde(rename_all = "snake_case")]
13pub enum AutomationType {
14 CreateFolder,
15 DeleteFile,
16 CopyFile,
17 MoveFile,
18 As2Send,
19 RunSync,
20 ImportFile,
21}
22
23#[derive(Debug, Clone, Serialize, Deserialize)]
25#[serde(rename_all = "snake_case")]
26pub enum AutomationTrigger {
27 Daily,
28 Custom,
29 Webhook,
30 Email,
31 Action,
32 Interval,
33}
34
35#[derive(Debug, Clone, Serialize, Deserialize)]
37pub struct AutomationEntity {
38 #[serde(skip_serializing_if = "Option::is_none")]
40 pub id: Option<i64>,
41
42 #[serde(skip_serializing_if = "Option::is_none")]
44 pub always_serialize_jobs: Option<bool>,
45
46 #[serde(skip_serializing_if = "Option::is_none")]
48 pub always_overwrite_size_matching_files: Option<bool>,
49
50 #[serde(skip_serializing_if = "Option::is_none")]
52 pub automation: Option<String>,
53
54 #[serde(skip_serializing_if = "Option::is_none")]
56 pub deleted: Option<bool>,
57
58 #[serde(skip_serializing_if = "Option::is_none")]
60 pub description: Option<String>,
61
62 #[serde(skip_serializing_if = "Option::is_none")]
64 pub destination_replace_from: Option<String>,
65
66 #[serde(skip_serializing_if = "Option::is_none")]
68 pub destination_replace_to: Option<String>,
69
70 #[serde(skip_serializing_if = "Option::is_none")]
72 pub destinations: Option<Vec<String>>,
73
74 #[serde(skip_serializing_if = "Option::is_none")]
76 pub disabled: Option<bool>,
77
78 #[serde(skip_serializing_if = "Option::is_none")]
80 pub exclude_pattern: Option<String>,
81
82 #[serde(skip_serializing_if = "Option::is_none")]
84 pub flatten_destination_structure: Option<bool>,
85
86 #[serde(skip_serializing_if = "Option::is_none")]
88 pub group_ids: Option<Vec<i64>>,
89
90 #[serde(skip_serializing_if = "Option::is_none")]
92 pub holiday_region: Option<String>,
93
94 #[serde(skip_serializing_if = "Option::is_none")]
96 pub human_readable_schedule: Option<String>,
97
98 #[serde(skip_serializing_if = "Option::is_none")]
100 pub ignore_locked_folders: Option<bool>,
101
102 #[serde(skip_serializing_if = "Option::is_none")]
104 pub import_urls: Option<Vec<serde_json::Value>>,
105
106 #[serde(skip_serializing_if = "Option::is_none")]
108 pub interval: Option<String>,
109
110 #[serde(skip_serializing_if = "Option::is_none")]
112 pub last_modified_at: Option<String>,
113
114 #[serde(skip_serializing_if = "Option::is_none")]
116 pub legacy_folder_matching: Option<bool>,
117
118 #[serde(skip_serializing_if = "Option::is_none")]
120 pub legacy_sync_ids: Option<Vec<i64>>,
121
122 #[serde(skip_serializing_if = "Option::is_none")]
124 pub name: Option<String>,
125
126 #[serde(skip_serializing_if = "Option::is_none")]
128 pub overwrite_files: Option<bool>,
129
130 #[serde(skip_serializing_if = "Option::is_none")]
132 pub path: Option<String>,
133
134 #[serde(skip_serializing_if = "Option::is_none")]
136 pub path_time_zone: Option<String>,
137
138 #[serde(skip_serializing_if = "Option::is_none")]
140 pub recurring_day: Option<i64>,
141
142 #[serde(skip_serializing_if = "Option::is_none")]
144 pub retry_on_failure_interval_in_minutes: Option<i64>,
145
146 #[serde(skip_serializing_if = "Option::is_none")]
148 pub retry_on_failure_number_of_attempts: Option<i64>,
149
150 #[serde(skip_serializing_if = "Option::is_none")]
152 pub schedule: Option<serde_json::Value>,
153
154 #[serde(skip_serializing_if = "Option::is_none")]
156 pub schedule_days_of_week: Option<Vec<i64>>,
157
158 #[serde(skip_serializing_if = "Option::is_none")]
160 pub schedule_time_zone: Option<String>,
161
162 #[serde(skip_serializing_if = "Option::is_none")]
164 pub schedule_times_of_day: Option<Vec<String>>,
165
166 #[serde(skip_serializing_if = "Option::is_none")]
168 pub source: Option<String>,
169
170 #[serde(skip_serializing_if = "Option::is_none")]
172 pub sync_ids: Option<Vec<i64>>,
173
174 #[serde(skip_serializing_if = "Option::is_none")]
176 pub trigger: Option<String>,
177
178 #[serde(skip_serializing_if = "Option::is_none")]
180 pub trigger_actions: Option<Vec<String>>,
181
182 #[serde(skip_serializing_if = "Option::is_none")]
184 pub user_id: Option<i64>,
185
186 #[serde(skip_serializing_if = "Option::is_none")]
188 pub user_ids: Option<Vec<i64>>,
189
190 #[serde(skip_serializing_if = "Option::is_none")]
192 pub value: Option<serde_json::Value>,
193
194 #[serde(skip_serializing_if = "Option::is_none")]
196 pub webhook_url: Option<String>,
197}
198
199pub struct AutomationHandler {
201 client: FilesClient,
202}
203
204impl AutomationHandler {
205 pub fn new(client: FilesClient) -> Self {
207 Self { client }
208 }
209
210 pub async fn list(
232 &self,
233 cursor: Option<&str>,
234 per_page: Option<i64>,
235 automation: Option<&str>,
236 ) -> Result<(Vec<AutomationEntity>, PaginationInfo)> {
237 let mut params = vec![];
238 if let Some(c) = cursor {
239 params.push(("cursor", c.to_string()));
240 }
241 if let Some(pp) = per_page {
242 params.push(("per_page", pp.to_string()));
243 }
244 if let Some(a) = automation {
245 params.push(("automation", a.to_string()));
246 }
247
248 let query = if params.is_empty() {
249 String::new()
250 } else {
251 format!(
252 "?{}",
253 params
254 .iter()
255 .map(|(k, v)| format!("{}={}", k, v))
256 .collect::<Vec<_>>()
257 .join("&")
258 )
259 };
260
261 let response = self
262 .client
263 .get_raw(&format!("/automations{}", query))
264 .await?;
265 let automations: Vec<AutomationEntity> = serde_json::from_value(response)?;
266
267 let pagination = PaginationInfo {
268 cursor_next: None,
269 cursor_prev: None,
270 };
271
272 Ok((automations, pagination))
273 }
274
275 pub async fn get(&self, id: i64) -> Result<AutomationEntity> {
280 let response = self.client.get_raw(&format!("/automations/{}", id)).await?;
281 Ok(serde_json::from_value(response)?)
282 }
283
284 #[allow(clippy::too_many_arguments)]
318 pub async fn create(
319 &self,
320 automation: &str,
321 source: Option<&str>,
322 destination: Option<&str>,
323 destinations: Option<Vec<String>>,
324 interval: Option<&str>,
325 path: Option<&str>,
326 trigger: Option<&str>,
327 ) -> Result<AutomationEntity> {
328 let mut request_body = json!({
329 "automation": automation,
330 });
331
332 if let Some(s) = source {
333 request_body["source"] = json!(s);
334 }
335 if let Some(d) = destination {
336 request_body["destination"] = json!(d);
337 }
338 if let Some(dests) = destinations {
339 request_body["destinations"] = json!(dests);
340 }
341 if let Some(i) = interval {
342 request_body["interval"] = json!(i);
343 }
344 if let Some(p) = path {
345 request_body["path"] = json!(p);
346 }
347 if let Some(t) = trigger {
348 request_body["trigger"] = json!(t);
349 }
350
351 let response = self.client.post_raw("/automations", request_body).await?;
352 Ok(serde_json::from_value(response)?)
353 }
354
355 #[allow(clippy::too_many_arguments)]
367 pub async fn update(
368 &self,
369 id: i64,
370 source: Option<&str>,
371 destination: Option<&str>,
372 interval: Option<&str>,
373 disabled: Option<bool>,
374 ) -> Result<AutomationEntity> {
375 let mut request_body = json!({});
376
377 if let Some(s) = source {
378 request_body["source"] = json!(s);
379 }
380 if let Some(d) = destination {
381 request_body["destination"] = json!(d);
382 }
383 if let Some(i) = interval {
384 request_body["interval"] = json!(i);
385 }
386 if let Some(dis) = disabled {
387 request_body["disabled"] = json!(dis);
388 }
389
390 let response = self
391 .client
392 .patch_raw(&format!("/automations/{}", id), request_body)
393 .await?;
394 Ok(serde_json::from_value(response)?)
395 }
396
397 pub async fn delete(&self, id: i64) -> Result<()> {
402 self.client
403 .delete_raw(&format!("/automations/{}", id))
404 .await?;
405 Ok(())
406 }
407
408 pub async fn manual_run(&self, id: i64) -> Result<serde_json::Value> {
416 let response = self
417 .client
418 .post_raw(&format!("/automations/{}/manual_run", id), json!({}))
419 .await?;
420 Ok(response)
421 }
422}
423
424#[cfg(test)]
425mod tests {
426 use super::*;
427
428 #[test]
429 fn test_handler_creation() {
430 let client = FilesClient::builder().api_key("test-key").build().unwrap();
431 let _handler = AutomationHandler::new(client);
432 }
433}