1use crate::cli::args::{AuditFormat, ShredMethod};
7use chrono::{DateTime, Utc};
8use serde::Serialize;
9use std::fs::File;
10use std::io::Write;
11use std::path::{Path, PathBuf};
12
13#[derive(Debug, Serialize, Clone)]
15pub struct ShredEvent {
16 pub path: PathBuf,
18 pub timestamp: DateTime<Utc>,
20 pub method: ShredMethod,
22 pub success: bool,
24 pub error: Option<String>,
26}
27
28#[derive(Debug, Serialize, Clone)]
30pub struct ShredReport {
31 pub generated_at: DateTime<Utc>,
33 pub total_files: usize,
35 pub success_count: usize,
37 pub failure_count: usize,
39 pub events: Vec<ShredEvent>,
41}
42
43impl ShredReport {
44 pub fn new(events: Vec<ShredEvent>) -> Self {
46 let total = events.len();
47 let success_count = events.iter().filter(|e| e.success).count();
48 let failure_count = total - success_count;
49
50 Self {
51 generated_at: Utc::now(),
52 total_files: total,
53 success_count,
54 failure_count,
55 events,
56 }
57 }
58
59 pub fn save(&self, path: &Path, format: AuditFormat) -> std::io::Result<()> {
61 let content = match format {
62 AuditFormat::Json => {
63 serde_json::to_string_pretty(self).map_err(std::io::Error::other)?
64 }
65 AuditFormat::Text => self.to_text(),
66 };
67
68 let mut file = File::create(path)?;
69 file.write_all(content.as_bytes())?;
70 Ok(())
71 }
72
73 fn to_text(&self) -> String {
74 let mut text = String::new();
75 text.push_str("=== sys-shred Forensic Audit Report ===\n");
76 text.push_str(&format!("Generated at: {}\n", self.generated_at));
77 text.push_str(&format!("Total Files: {}\n", self.total_files));
78 text.push_str(&format!("Successes: {}\n", self.success_count));
79 text.push_str(&format!("Failures: {}\n", self.failure_count));
80 text.push_str("========================================\n\n");
81
82 for event in &self.events {
83 let status = if event.success { "SUCCESS" } else { "FAILURE" };
84 text.push_str(&format!(
85 "[{}] {:?} - {} ({:?})\n",
86 event.timestamp.format("%Y-%m-%d %H:%M:%S"),
87 event.path,
88 status,
89 event.method
90 ));
91 if let Some(ref err) = event.error {
92 text.push_str(&format!(" Error: {}\n", err));
93 }
94 }
95
96 text
97 }
98}