use axum::Extension;
use axum::Json;
use axum::body::Bytes;
use axum::http::HeaderMap;
use axum::response::{IntoResponse, Response};
use serde::{Deserialize, Serialize};
use crate::writer::build_flag_reporter_audit_reason;
use super::common::{AdminError, AdminState, verify_and_authorize};
const LXM: &str = "tools.cairn.admin.flagReporter";
#[derive(Debug, Deserialize)]
struct Input {
did: String,
suppressed: bool,
#[serde(default)]
reason: Option<String>,
}
#[derive(Debug, Serialize)]
struct Output {}
pub(super) async fn handler(
Extension(state): Extension<AdminState>,
headers: HeaderMap,
body: Bytes,
) -> Response {
let admin = match verify_and_authorize(&state, &headers, LXM).await {
Ok(v) => v,
Err(e) => return e.into_response(),
};
let input: Input = match serde_json::from_slice(&body) {
Ok(v) => v,
Err(_) => return AdminError::InvalidRequest("malformed request body").into_response(),
};
if !input.did.starts_with("did:") {
return AdminError::InvalidRequest("did must start with did:").into_response();
}
let mut tx = match state.pool.begin().await {
Ok(t) => t,
Err(_) => return AdminError::Internal.into_response(),
};
let now_ms = crate::writer::epoch_ms_now();
let audit_reason =
build_flag_reporter_audit_reason(&input.did, input.suppressed, input.reason.as_deref());
if input.suppressed {
let res = sqlx::query!(
"INSERT INTO suppressed_reporters (did, suppressed_by, suppressed_at, reason)
VALUES (?1, ?2, ?3, ?4)
ON CONFLICT(did) DO UPDATE SET
suppressed_by = excluded.suppressed_by,
suppressed_at = excluded.suppressed_at,
reason = excluded.reason",
input.did,
admin.caller_did,
now_ms,
input.reason,
)
.execute(&mut *tx)
.await;
if res.is_err() {
return AdminError::Internal.into_response();
}
let action = "reporter_flagged";
let outcome = "success";
let res = sqlx::query!(
"INSERT INTO audit_log (created_at, action, actor_did, target, target_cid, outcome, reason)
VALUES (?1, ?2, ?3, ?4, NULL, ?5, ?6)",
now_ms,
action,
admin.caller_did,
input.did,
outcome,
audit_reason,
)
.execute(&mut *tx)
.await;
if res.is_err() {
return AdminError::Internal.into_response();
}
} else {
let res = sqlx::query!("DELETE FROM suppressed_reporters WHERE did = ?1", input.did)
.execute(&mut *tx)
.await;
if res.is_err() {
return AdminError::Internal.into_response();
}
let action = "reporter_unflagged";
let outcome = "success";
let res = sqlx::query!(
"INSERT INTO audit_log (created_at, action, actor_did, target, target_cid, outcome, reason)
VALUES (?1, ?2, ?3, ?4, NULL, ?5, ?6)",
now_ms,
action,
admin.caller_did,
input.did,
outcome,
audit_reason,
)
.execute(&mut *tx)
.await;
if res.is_err() {
return AdminError::Internal.into_response();
}
}
if tx.commit().await.is_err() {
return AdminError::Internal.into_response();
}
Json(Output {}).into_response()
}