1use crate::{FilesClient, PaginationInfo, Result};
7use serde::{Deserialize, Serialize};
8use serde_json::json;
9
10#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct HistoryExportEntity {
13 #[serde(skip_serializing_if = "Option::is_none")]
15 pub id: Option<i64>,
16
17 #[serde(skip_serializing_if = "Option::is_none")]
19 pub history_version: Option<String>,
20
21 #[serde(skip_serializing_if = "Option::is_none")]
23 pub start_at: Option<String>,
24
25 #[serde(skip_serializing_if = "Option::is_none")]
27 pub end_at: Option<String>,
28
29 #[serde(skip_serializing_if = "Option::is_none")]
31 pub status: Option<String>,
32
33 #[serde(skip_serializing_if = "Option::is_none")]
35 pub query_action: Option<String>,
36
37 #[serde(skip_serializing_if = "Option::is_none")]
39 pub query_interface: Option<String>,
40
41 #[serde(skip_serializing_if = "Option::is_none")]
43 pub query_user_id: Option<String>,
44
45 #[serde(skip_serializing_if = "Option::is_none")]
47 pub query_file_id: Option<String>,
48
49 #[serde(skip_serializing_if = "Option::is_none")]
51 pub query_parent_id: Option<String>,
52
53 #[serde(skip_serializing_if = "Option::is_none")]
55 pub query_path: Option<String>,
56
57 #[serde(skip_serializing_if = "Option::is_none")]
59 pub query_folder: Option<String>,
60
61 #[serde(skip_serializing_if = "Option::is_none")]
63 pub query_src: Option<String>,
64
65 #[serde(skip_serializing_if = "Option::is_none")]
67 pub query_destination: Option<String>,
68
69 #[serde(skip_serializing_if = "Option::is_none")]
71 pub query_ip: Option<String>,
72
73 #[serde(skip_serializing_if = "Option::is_none")]
75 pub query_username: Option<String>,
76
77 #[serde(skip_serializing_if = "Option::is_none")]
79 pub query_failure_type: Option<String>,
80
81 #[serde(skip_serializing_if = "Option::is_none")]
83 pub query_target_id: Option<String>,
84
85 #[serde(skip_serializing_if = "Option::is_none")]
87 pub query_target_name: Option<String>,
88
89 #[serde(skip_serializing_if = "Option::is_none")]
91 pub query_target_permission: Option<String>,
92
93 #[serde(skip_serializing_if = "Option::is_none")]
95 pub query_target_user_id: Option<String>,
96
97 #[serde(skip_serializing_if = "Option::is_none")]
99 pub query_target_username: Option<String>,
100
101 #[serde(skip_serializing_if = "Option::is_none")]
103 pub query_target_platform: Option<String>,
104
105 #[serde(skip_serializing_if = "Option::is_none")]
107 pub query_target_permission_set: Option<String>,
108
109 #[serde(skip_serializing_if = "Option::is_none")]
111 pub results_url: Option<String>,
112}
113
114#[derive(Debug, Clone, Serialize, Deserialize)]
116pub struct HistoryExportResultEntity {
117 #[serde(skip_serializing_if = "Option::is_none")]
119 pub history_export_id: Option<i64>,
120
121 #[serde(skip_serializing_if = "Option::is_none")]
123 pub result: Option<serde_json::Value>,
124}
125
126pub struct HistoryHandler {
128 client: FilesClient,
129}
130
131impl HistoryHandler {
132 pub fn new(client: FilesClient) -> Self {
134 Self { client }
135 }
136
137 pub async fn list_for_file(
147 &self,
148 path: &str,
149 cursor: Option<&str>,
150 per_page: Option<i64>,
151 ) -> Result<(Vec<serde_json::Value>, PaginationInfo)> {
152 let mut params = vec![];
153 if let Some(c) = cursor {
154 params.push(("cursor", c.to_string()));
155 }
156 if let Some(pp) = per_page {
157 params.push(("per_page", pp.to_string()));
158 }
159
160 let query = if params.is_empty() {
161 String::new()
162 } else {
163 format!(
164 "?{}",
165 params
166 .iter()
167 .map(|(k, v)| format!("{}={}", k, v))
168 .collect::<Vec<_>>()
169 .join("&")
170 )
171 };
172
173 let response = self
174 .client
175 .get_raw(&format!("/history/files/{}{}", path, query))
176 .await?;
177 let history: Vec<serde_json::Value> = serde_json::from_value(response)?;
178
179 let pagination = PaginationInfo {
180 cursor_next: None,
181 cursor_prev: None,
182 };
183
184 Ok((history, pagination))
185 }
186
187 pub async fn list_for_folder(
194 &self,
195 path: &str,
196 cursor: Option<&str>,
197 per_page: Option<i64>,
198 ) -> Result<(Vec<serde_json::Value>, PaginationInfo)> {
199 let mut params = vec![];
200 if let Some(c) = cursor {
201 params.push(("cursor", c.to_string()));
202 }
203 if let Some(pp) = per_page {
204 params.push(("per_page", pp.to_string()));
205 }
206
207 let query = if params.is_empty() {
208 String::new()
209 } else {
210 format!(
211 "?{}",
212 params
213 .iter()
214 .map(|(k, v)| format!("{}={}", k, v))
215 .collect::<Vec<_>>()
216 .join("&")
217 )
218 };
219
220 let response = self
221 .client
222 .get_raw(&format!("/history/folders/{}{}", path, query))
223 .await?;
224 let history: Vec<serde_json::Value> = serde_json::from_value(response)?;
225
226 let pagination = PaginationInfo {
227 cursor_next: None,
228 cursor_prev: None,
229 };
230
231 Ok((history, pagination))
232 }
233
234 pub async fn list_for_user(
241 &self,
242 user_id: i64,
243 cursor: Option<&str>,
244 per_page: Option<i64>,
245 ) -> Result<(Vec<serde_json::Value>, PaginationInfo)> {
246 let mut params = vec![];
247 if let Some(c) = cursor {
248 params.push(("cursor", c.to_string()));
249 }
250 if let Some(pp) = per_page {
251 params.push(("per_page", pp.to_string()));
252 }
253
254 let query = if params.is_empty() {
255 String::new()
256 } else {
257 format!(
258 "?{}",
259 params
260 .iter()
261 .map(|(k, v)| format!("{}={}", k, v))
262 .collect::<Vec<_>>()
263 .join("&")
264 )
265 };
266
267 let response = self
268 .client
269 .get_raw(&format!("/history/users/{}{}", user_id, query))
270 .await?;
271 let history: Vec<serde_json::Value> = serde_json::from_value(response)?;
272
273 let pagination = PaginationInfo {
274 cursor_next: None,
275 cursor_prev: None,
276 };
277
278 Ok((history, pagination))
279 }
280
281 pub async fn list_logins(
287 &self,
288 cursor: Option<&str>,
289 per_page: Option<i64>,
290 ) -> Result<(Vec<serde_json::Value>, PaginationInfo)> {
291 let mut params = vec![];
292 if let Some(c) = cursor {
293 params.push(("cursor", c.to_string()));
294 }
295 if let Some(pp) = per_page {
296 params.push(("per_page", pp.to_string()));
297 }
298
299 let query = if params.is_empty() {
300 String::new()
301 } else {
302 format!(
303 "?{}",
304 params
305 .iter()
306 .map(|(k, v)| format!("{}={}", k, v))
307 .collect::<Vec<_>>()
308 .join("&")
309 )
310 };
311
312 let response = self
313 .client
314 .get_raw(&format!("/history/login{}", query))
315 .await?;
316 let history: Vec<serde_json::Value> = serde_json::from_value(response)?;
317
318 let pagination = PaginationInfo {
319 cursor_next: None,
320 cursor_prev: None,
321 };
322
323 Ok((history, pagination))
324 }
325
326 #[allow(clippy::too_many_arguments)]
338 pub async fn create_export(
339 &self,
340 start_at: Option<&str>,
341 end_at: Option<&str>,
342 query_action: Option<&str>,
343 query_user_id: Option<&str>,
344 query_folder: Option<&str>,
345 ) -> Result<HistoryExportEntity> {
346 let mut request_body = json!({});
347
348 if let Some(start) = start_at {
349 request_body["start_at"] = json!(start);
350 }
351 if let Some(end) = end_at {
352 request_body["end_at"] = json!(end);
353 }
354 if let Some(action) = query_action {
355 request_body["query_action"] = json!(action);
356 }
357 if let Some(user) = query_user_id {
358 request_body["query_user_id"] = json!(user);
359 }
360 if let Some(folder) = query_folder {
361 request_body["query_folder"] = json!(folder);
362 }
363
364 let response = self
365 .client
366 .post_raw("/history_exports", request_body)
367 .await?;
368 Ok(serde_json::from_value(response)?)
369 }
370
371 pub async fn get_export(&self, id: i64) -> Result<HistoryExportEntity> {
376 let response = self
377 .client
378 .get_raw(&format!("/history_exports/{}", id))
379 .await?;
380 Ok(serde_json::from_value(response)?)
381 }
382
383 pub async fn get_export_results(
390 &self,
391 cursor: Option<&str>,
392 per_page: Option<i64>,
393 history_export_id: Option<i64>,
394 ) -> Result<(Vec<HistoryExportResultEntity>, PaginationInfo)> {
395 let mut params = vec![];
396 if let Some(c) = cursor {
397 params.push(("cursor", c.to_string()));
398 }
399 if let Some(pp) = per_page {
400 params.push(("per_page", pp.to_string()));
401 }
402 if let Some(export_id) = history_export_id {
403 params.push(("history_export_id", export_id.to_string()));
404 }
405
406 let query = if params.is_empty() {
407 String::new()
408 } else {
409 format!(
410 "?{}",
411 params
412 .iter()
413 .map(|(k, v)| format!("{}={}", k, v))
414 .collect::<Vec<_>>()
415 .join("&")
416 )
417 };
418
419 let response = self
420 .client
421 .get_raw(&format!("/history_export_results{}", query))
422 .await?;
423 let results: Vec<HistoryExportResultEntity> = serde_json::from_value(response)?;
424
425 let pagination = PaginationInfo {
426 cursor_next: None,
427 cursor_prev: None,
428 };
429
430 Ok((results, pagination))
431 }
432}
433
434#[cfg(test)]
435mod tests {
436 use super::*;
437
438 #[test]
439 fn test_handler_creation() {
440 let client = FilesClient::builder().api_key("test-key").build().unwrap();
441 let _handler = HistoryHandler::new(client);
442 }
443}