use std::time::SystemTime;
use axum::Extension;
use axum::Json;
use axum::extract::RawQuery;
use axum::http::HeaderMap;
use axum::response::{IntoResponse, Response};
use super::common::{AdminError, AdminState, verify_and_authorize};
use crate::server::strike_state::{build_strike_state_view, subject_has_history};
const LXM: &str = "tools.cairn.admin.getSubjectStrikes";
pub(super) async fn handler(
Extension(state): Extension<AdminState>,
headers: HeaderMap,
RawQuery(query): RawQuery,
) -> Response {
if let Err(e) = verify_and_authorize(&state, &headers, LXM).await {
return e.into_response();
}
let subject = match parse_subject(query.as_deref().unwrap_or("")) {
Ok(s) => s,
Err(e) => return e.into_response(),
};
match subject_has_history(&state.pool, &subject).await {
Ok(true) => {}
Ok(false) => return AdminError::SubjectNotFound.into_response(),
Err(_) => return AdminError::Internal.into_response(),
}
let view = match build_strike_state_view(
&state.pool,
&subject,
&state.config.service_did,
&state.strike_policy,
SystemTime::now(),
)
.await
{
Ok(v) => v,
Err(_) => return AdminError::Internal.into_response(),
};
Json(view).into_response()
}
fn parse_subject(raw: &str) -> Result<String, AdminError> {
let mut subject: Option<String> = None;
for (k, v) in form_urlencoded::parse(raw.as_bytes()) {
if k == "subject" && !v.is_empty() {
subject = Some(v.into_owned());
}
}
let subject = subject.ok_or(AdminError::InvalidRequest("subject is required"))?;
if !subject.starts_with("did:") {
return Err(AdminError::InvalidRequest("subject must be a DID"));
}
Ok(subject)
}