diff --git a/src-tauri/src/proxmox/updates.rs b/src-tauri/src/proxmox/updates.rs index 8baf8b9f..90d86ec3 100644 --- a/src-tauri/src/proxmox/updates.rs +++ b/src-tauri/src/proxmox/updates.rs @@ -22,18 +22,141 @@ pub struct UpdateStatus { /// Check for updates pub async fn check_updates( - _client: &crate::proxmox::client::ProxmoxClient, - _ticket: &str, + client: &crate::proxmox::client::ProxmoxClient, + ticket: &str, ) -> Result { - Err("Not implemented yet".to_string()) + let path = "nodes/self/update"; + let response: serde_json::Value = client + .get(path, Some(ticket)) + .await + .map_err(|e| format!("Failed to check for updates: {}", e))?; + + let checked_at = chrono::Utc::now().format("%Y-%m-%d %H:%M:%S").to_string(); + + let updates: Vec = response + .get("data") + .and_then(|d| d.as_array()) + .unwrap_or(&Vec::new()) + .iter() + .filter_map(|update| { + let package = update.get("package")?.as_str()?.to_string(); + let version = update.get("version")?.as_str()?.to_string(); + let available_version = update.get("available")?.as_str().unwrap_or("").to_string(); + let size = update.get("size")?.as_u64().unwrap_or(0); + + Some(UpdateInfo { + package, + version, + available_version, + size, + }) + }) + .collect(); + + let update_count = updates.len() as u32; + + Ok(UpdateStatus { + checked_at, + updates, + update_count, + }) } /// List available updates pub async fn list_updates( - _client: &crate::proxmox::client::ProxmoxClient, - _ticket: &str, + client: &crate::proxmox::client::ProxmoxClient, + ticket: &str, ) -> Result, String> { - Err("Not implemented yet".to_string()) + let path = "nodes/self/update"; + let response: serde_json::Value = client + .get(path, Some(ticket)) + .await + .map_err(|e| format!("Failed to list updates: {}", e))?; + + let updates: Vec = response + .get("data") + .and_then(|d| d.as_array()) + .map(|arr| { + arr.iter() + .filter_map(|update| { + let package = update.get("package")?.as_str()?.to_string(); + let version = update.get("version")?.as_str()?.to_string(); + let available_version = update.get("available")?.as_str().unwrap_or("").to_string(); + let size = update.get("size")?.as_u64().unwrap_or(0); + + Some(UpdateInfo { + package, + version, + available_version, + size, + }) + }) + .collect() + }) + .unwrap_or_default(); + + Ok(updates) +} + +/// Get update status +pub async fn get_update_status( + client: &crate::proxmox::client::ProxmoxClient, + ticket: &str, +) -> Result { + let path = "nodes/self/update/status"; + client + .get(path, Some(ticket)) + .await + .map_err(|e| format!("Failed to get update status: {}", e)) +} + +/// Refresh update list +pub async fn refresh_updates( + client: &crate::proxmox::client::ProxmoxClient, + ticket: &str, +) -> Result<(), String> { + let path = "nodes/self/update"; + let _response: serde_json::Value = client + .post(path, &serde_json::json!({}), Some(ticket)) + .await + .map_err(|e| format!("Failed to refresh updates: {}", e))?; + Ok(()) +} + +/// Install updates +pub async fn install_updates( + client: &crate::proxmox::client::ProxmoxClient, + packages: &[&str], + ticket: &str, +) -> Result<(), String> { + let path = "nodes/self/update"; + let config = serde_json::json!({ + "packages": packages + }); + + let _response: serde_json::Value = client + .post(path, &config, Some(ticket)) + .await + .map_err(|e| format!("Failed to install updates: {}", e))?; + Ok(()) +} + +/// Get update history +pub async fn get_update_history( + client: &crate::proxmox::client::ProxmoxClient, + ticket: &str, +) -> Result, String> { + let path = "nodes/self/update/history"; + let response: serde_json::Value = client + .get(path, Some(ticket)) + .await + .map_err(|e| format!("Failed to get update history: {}", e))?; + + if let Some(history) = response.get("data").and_then(|d| d.as_array()) { + Ok(history.to_vec()) + } else { + Err("Invalid response format: missing 'data' field".to_string()) + } } #[cfg(test)] @@ -55,4 +178,18 @@ mod tests { assert_eq!(update.package, deserialized.package); assert_eq!(update.available_version, deserialized.available_version); } + + #[test] + fn test_update_status_serialization() { + let status = UpdateStatus { + checked_at: "2026-06-10 14:30:00".to_string(), + updates: vec![], + update_count: 0, + }; + + let json = serde_json::to_string(&status).unwrap(); + let deserialized: UpdateStatus = serde_json::from_str(&json).unwrap(); + + assert_eq!(status.checked_at, deserialized.checked_at); + } }