use axum::extract::{Path, State};
use axum::{Json, http::StatusCode};
use serde::Serialize;
use did_hosting_common::server::auth::extractor::AdminAuth;
use crate::error::AppError;
use crate::server::AppState;
#[derive(Debug, Serialize)]
pub struct GenerationView {
pub id: u64,
pub did: String,
pub current: bool,
pub signing_kid: String,
pub key_agreement_kid: String,
pub mediator_did: Option<String>,
pub didcomm: bool,
pub tsp: bool,
pub created_at: u64,
pub retired_at: Option<u64>,
pub expires_at: Option<u64>,
}
#[derive(Debug, Serialize)]
pub struct GenerationsResponse {
pub generations: Vec<GenerationView>,
pub rotation_grace_secs: u64,
}
pub async fn list_generations(
_auth: AdminAuth,
State(state): State<AppState>,
) -> Result<Json<GenerationsResponse>, AppError> {
let Some(identity) = state.identity.as_ref() else {
return Ok(Json(GenerationsResponse {
generations: Vec::new(),
rotation_grace_secs: state.config.identity.rotation_grace_secs(),
}));
};
let generations = identity.generations();
let current_id = generations.first().map(|g| g.id);
Ok(Json(GenerationsResponse {
generations: generations
.iter()
.map(|g| GenerationView {
id: g.id,
did: g.did.clone(),
current: Some(g.id) == current_id,
signing_kid: g.signing_kid.clone(),
key_agreement_kid: g.ka_kid.clone(),
mediator_did: g.mediator_did.clone(),
didcomm: g.protocols.didcomm,
tsp: g.protocols.tsp,
created_at: g.created_at,
retired_at: g.retired_at,
expires_at: g.expires_at,
})
.collect(),
rotation_grace_secs: state.config.identity.rotation_grace_secs(),
}))
}
pub async fn retire_generation(
_auth: AdminAuth,
State(state): State<AppState>,
Path(id): Path<u64>,
) -> Result<StatusCode, AppError> {
crate::identity_rotation::retire_generation_now(&state, id).await?;
Ok(StatusCode::NO_CONTENT)
}