Skip to main content

zoi_cli/cmd/
history.rs

1use crate::pkg::audit;
2use anyhow::{Result, anyhow};
3use colored::*;
4use comfy_table::{Cell, Color, ContentArrangement, Table, presets::UTF8_FULL};
5use std::path::PathBuf;
6
7pub fn run(verify: bool, export: Option<PathBuf>, ndjson: bool) -> Result<()> {
8    if verify {
9        let report = audit::verify_chain()?;
10        if report.valid {
11            println!(
12                "{} {} (entries: {}, chained: {}, legacy: {})",
13                "::".bold().blue(),
14                report.message.green(),
15                report.total_entries,
16                report.hashed_entries,
17                report.legacy_entries
18            );
19            return Ok(());
20        }
21        return Err(anyhow!(report.message));
22    }
23
24    if let Some(path) = export {
25        let total = audit::export_history(&path, ndjson)?;
26        println!(
27            "{} Exported {} audit entr{} to {} (format: {}).",
28            "::".bold().green(),
29            total,
30            if total == 1 { "y" } else { "ies" },
31            path.display().to_string().cyan(),
32            if ndjson { "ndjson" } else { "json" }
33        );
34        return Ok(());
35    }
36
37    println!("{} Zoi operation history...", "::".bold().blue());
38
39    let history = audit::get_history()?;
40
41    if history.is_empty() {
42        println!("No history recorded. Audit logging might be disabled.");
43        return Ok(());
44    }
45
46    let mut table = Table::new();
47    table
48        .load_preset(UTF8_FULL)
49        .set_content_arrangement(ContentArrangement::Dynamic)
50        .set_header(vec![
51            "Date/Time",
52            "User",
53            "Action",
54            "Package",
55            "Version",
56            "Repo",
57            "Type",
58            "Scope",
59        ]);
60
61    for entry in history {
62        let action_cell = match entry.action {
63            audit::AuditAction::Install => Cell::new("Install").fg(Color::Green),
64            audit::AuditAction::Uninstall => Cell::new("Uninstall").fg(Color::Red),
65            audit::AuditAction::Upgrade => Cell::new("Upgrade").fg(Color::Yellow),
66        };
67
68        table.add_row(vec![
69            Cell::new(
70                entry
71                    .timestamp
72                    .with_timezone(&chrono::Local)
73                    .format("%Y-%m-%d %H:%M:%S"),
74            ),
75            Cell::new(entry.user),
76            action_cell,
77            Cell::new(entry.package_name).fg(Color::Cyan),
78            Cell::new(entry.version),
79            Cell::new(entry.repo),
80            Cell::new(format!("{:?}", entry.package_type)),
81            Cell::new(format!("{:?}", entry.scope)),
82        ]);
83    }
84
85    println!("{table}");
86
87    Ok(())
88}