acme_proxy_admin/webadmin/pages/
audit.rs1use axum::extract::{Path, Query, State};
9use axum::response::Html;
10use serde_json::Value;
11
12use crate::admin;
13use crate::webadmin::AdminState;
14use crate::webadmin::error::AdminError;
15use crate::webadmin::handlers::audit::AuditListParams;
16use crate::webadmin::handlers::paging::PageParams;
17use crate::webadmin::pages::auth::PageSession;
18use crate::webadmin::pages::error::PageError;
19use crate::webadmin::pages::{ListFilters, chrome, page_value, pager, respond};
20use acme_proxy_core::audit::ALL_AUDIT_EVENTS;
21use acme_proxy_store::audit::AuditEntry;
22use acme_proxy_store::audit::AuditQuery;
23
24pub async fn list_audit(
26 State(state): State<AdminState>,
27 Query(params): Query<AuditListParams>,
28 session: PageSession,
29) -> Result<Html<String>, PageError> {
30 let page = PageParams::from(params.limit, params.offset).resolve(&state.config);
31 let filters = ListFilters::new()
34 .with("profile", params.profile.as_deref())
35 .with("event", params.event.as_deref())
36 .with("outcome", params.outcome.as_deref())
37 .with("accountId", params.account_id.as_deref())
38 .with("orderId", params.order_id.as_deref())
39 .with("certSerial", params.cert_serial.as_deref());
40
41 let (entries, total) = admin::list_audit(
42 &AuditQuery {
43 profile: params.profile.clone(),
44 account_id: params.account_id.clone(),
45 order_id: params.order_id.clone(),
46 cert_serial: params.cert_serial.clone(),
47 event: params.event.clone(),
48 outcome: params.outcome.clone(),
49 since: None,
50 limit: page.limit,
51 offset: page.offset,
52 },
53 state.database.clone(),
54 )
55 .await?;
56
57 let items: Vec<Value> = entries.iter().map(AuditEntry::to_json).collect();
58 let mut context = chrome(&session, "audit", "Audit");
59 context.insert("page".to_string(), page_value(items, total));
60 context.insert(
61 "pager".to_string(),
62 pager(page, total, "/ui/audit", &filters.pairs(), "#audit-table"),
63 );
64 context.insert("filters".to_string(), filters.to_value());
65 context.insert(
66 "events".to_string(),
67 Value::Array(
68 ALL_AUDIT_EVENTS
69 .iter()
70 .map(|event| Value::from(event.as_str()))
71 .collect(),
72 ),
73 );
74 context.insert(
75 "profiles".to_string(),
76 Value::Array(crate::webadmin::handlers::misc::profile_rows(&state)),
77 );
78
79 respond(
80 &state,
81 session.hx,
82 "audit/list.html",
83 "audit/_table.html",
84 context,
85 )
86}
87
88pub async fn get_audit(
90 State(state): State<AdminState>,
91 Path(id): Path<i64>,
92 session: PageSession,
93) -> Result<Html<String>, PageError> {
94 let entry = admin::find_audit(id, state.database.clone())
95 .await?
96 .ok_or_else(|| not_found(id))?;
97
98 let mut context = chrome(&session, "audit", &format!("Audit {id}"));
99 context.insert("entry".to_string(), entry.to_json());
100 respond(
101 &state,
102 session.hx,
103 "audit/detail.html",
104 "audit/_card.html",
105 context,
106 )
107}
108
109fn not_found(id: i64) -> PageError {
110 AdminError::not_found(format!("audit row {id} not found")).into()
111}