use axum::Extension;
use axum::Json;
use axum::http::HeaderMap;
use axum::response::{IntoResponse, Response};
use serde::Serialize;
use crate::writer::{SweepRequest, build_retention_sweep_audit_reason};
use super::common::{AdminError, AdminState, verify_and_authorize_admin_only};
const LXM: &str = "tools.cairn.admin.retentionSweep";
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
struct Output {
rows_deleted: i64,
batches: u64,
duration_ms: u64,
#[serde(skip_serializing_if = "Option::is_none")]
retention_days_applied: Option<u32>,
}
pub(super) async fn handler(
Extension(state): Extension<AdminState>,
headers: HeaderMap,
) -> Response {
let admin = match verify_and_authorize_admin_only(&state, &headers, LXM).await {
Ok(v) => v,
Err(e) => return e.into_response(),
};
let result = match state.writer.sweep(SweepRequest).await {
Ok(r) => r,
Err(_) => return AdminError::Internal.into_response(),
};
let now_ms = crate::writer::epoch_ms_now();
let action = "retention_sweep";
let outcome = "success";
let reason = build_retention_sweep_audit_reason(&result);
if sqlx::query!(
"INSERT INTO audit_log (created_at, action, actor_did, target, target_cid, outcome, reason)
VALUES (?1, ?2, ?3, NULL, NULL, ?4, ?5)",
now_ms,
action,
admin.caller_did,
outcome,
reason,
)
.execute(&state.pool)
.await
.is_err()
{
return AdminError::Internal.into_response();
}
Json(Output {
rows_deleted: result.rows_deleted,
batches: result.batches,
duration_ms: result.duration_ms,
retention_days_applied: result.retention_days_applied,
})
.into_response()
}