use crate::{FilesClient, PaginationInfo, Result};
use serde::{Deserialize, Serialize};
use serde_json::json;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HistoryExportEntity {
#[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub history_version: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub start_at: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub end_at: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub status: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub query_action: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub query_interface: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub query_user_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub query_file_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub query_parent_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub query_path: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub query_folder: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub query_src: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub query_destination: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub query_ip: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub query_username: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub query_failure_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub query_target_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub query_target_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub query_target_permission: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub query_target_user_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub query_target_username: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub query_target_platform: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub query_target_permission_set: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub results_url: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HistoryExportResultEntity {
#[serde(skip_serializing_if = "Option::is_none")]
pub history_export_id: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub result: Option<serde_json::Value>,
}
pub struct HistoryHandler {
client: FilesClient,
}
impl HistoryHandler {
pub fn new(client: FilesClient) -> Self {
Self { client }
}
pub async fn list_for_file(
&self,
path: &str,
cursor: Option<&str>,
per_page: Option<i64>,
) -> Result<(Vec<serde_json::Value>, PaginationInfo)> {
let mut params = vec![];
if let Some(c) = cursor {
params.push(("cursor", c.to_string()));
}
if let Some(pp) = per_page {
params.push(("per_page", pp.to_string()));
}
let query = if params.is_empty() {
String::new()
} else {
format!(
"?{}",
params
.iter()
.map(|(k, v)| format!("{}={}", k, v))
.collect::<Vec<_>>()
.join("&")
)
};
let response = self
.client
.get_raw(&format!("/history/files/{}{}", path, query))
.await?;
let history: Vec<serde_json::Value> = serde_json::from_value(response)?;
let pagination = PaginationInfo {
cursor_next: None,
cursor_prev: None,
};
Ok((history, pagination))
}
pub async fn list_for_folder(
&self,
path: &str,
cursor: Option<&str>,
per_page: Option<i64>,
) -> Result<(Vec<serde_json::Value>, PaginationInfo)> {
let mut params = vec![];
if let Some(c) = cursor {
params.push(("cursor", c.to_string()));
}
if let Some(pp) = per_page {
params.push(("per_page", pp.to_string()));
}
let query = if params.is_empty() {
String::new()
} else {
format!(
"?{}",
params
.iter()
.map(|(k, v)| format!("{}={}", k, v))
.collect::<Vec<_>>()
.join("&")
)
};
let response = self
.client
.get_raw(&format!("/history/folders/{}{}", path, query))
.await?;
let history: Vec<serde_json::Value> = serde_json::from_value(response)?;
let pagination = PaginationInfo {
cursor_next: None,
cursor_prev: None,
};
Ok((history, pagination))
}
pub async fn list_for_user(
&self,
user_id: i64,
cursor: Option<&str>,
per_page: Option<i64>,
) -> Result<(Vec<serde_json::Value>, PaginationInfo)> {
let mut params = vec![];
if let Some(c) = cursor {
params.push(("cursor", c.to_string()));
}
if let Some(pp) = per_page {
params.push(("per_page", pp.to_string()));
}
let query = if params.is_empty() {
String::new()
} else {
format!(
"?{}",
params
.iter()
.map(|(k, v)| format!("{}={}", k, v))
.collect::<Vec<_>>()
.join("&")
)
};
let response = self
.client
.get_raw(&format!("/history/users/{}{}", user_id, query))
.await?;
let history: Vec<serde_json::Value> = serde_json::from_value(response)?;
let pagination = PaginationInfo {
cursor_next: None,
cursor_prev: None,
};
Ok((history, pagination))
}
pub async fn list_logins(
&self,
cursor: Option<&str>,
per_page: Option<i64>,
) -> Result<(Vec<serde_json::Value>, PaginationInfo)> {
let mut params = vec![];
if let Some(c) = cursor {
params.push(("cursor", c.to_string()));
}
if let Some(pp) = per_page {
params.push(("per_page", pp.to_string()));
}
let query = if params.is_empty() {
String::new()
} else {
format!(
"?{}",
params
.iter()
.map(|(k, v)| format!("{}={}", k, v))
.collect::<Vec<_>>()
.join("&")
)
};
let response = self
.client
.get_raw(&format!("/history/login{}", query))
.await?;
let history: Vec<serde_json::Value> = serde_json::from_value(response)?;
let pagination = PaginationInfo {
cursor_next: None,
cursor_prev: None,
};
Ok((history, pagination))
}
#[allow(clippy::too_many_arguments)]
pub async fn create_export(
&self,
start_at: Option<&str>,
end_at: Option<&str>,
query_action: Option<&str>,
query_user_id: Option<&str>,
query_folder: Option<&str>,
) -> Result<HistoryExportEntity> {
let mut request_body = json!({});
if let Some(start) = start_at {
request_body["start_at"] = json!(start);
}
if let Some(end) = end_at {
request_body["end_at"] = json!(end);
}
if let Some(action) = query_action {
request_body["query_action"] = json!(action);
}
if let Some(user) = query_user_id {
request_body["query_user_id"] = json!(user);
}
if let Some(folder) = query_folder {
request_body["query_folder"] = json!(folder);
}
let response = self
.client
.post_raw("/history_exports", request_body)
.await?;
Ok(serde_json::from_value(response)?)
}
pub async fn get_export(&self, id: i64) -> Result<HistoryExportEntity> {
let response = self
.client
.get_raw(&format!("/history_exports/{}", id))
.await?;
Ok(serde_json::from_value(response)?)
}
pub async fn get_export_results(
&self,
cursor: Option<&str>,
per_page: Option<i64>,
history_export_id: Option<i64>,
) -> Result<(Vec<HistoryExportResultEntity>, PaginationInfo)> {
let mut params = vec![];
if let Some(c) = cursor {
params.push(("cursor", c.to_string()));
}
if let Some(pp) = per_page {
params.push(("per_page", pp.to_string()));
}
if let Some(export_id) = history_export_id {
params.push(("history_export_id", export_id.to_string()));
}
let query = if params.is_empty() {
String::new()
} else {
format!(
"?{}",
params
.iter()
.map(|(k, v)| format!("{}={}", k, v))
.collect::<Vec<_>>()
.join("&")
)
};
let response = self
.client
.get_raw(&format!("/history_export_results{}", query))
.await?;
let results: Vec<HistoryExportResultEntity> = serde_json::from_value(response)?;
let pagination = PaginationInfo {
cursor_next: None,
cursor_prev: None,
};
Ok((results, pagination))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_handler_creation() {
let client = FilesClient::builder().api_key("test-key").build().unwrap();
let _handler = HistoryHandler::new(client);
}
}