use axum::{Json, extract::Query, http::StatusCode, response::IntoResponse};
use super::{
ErrorResponse, RequestCtx, SiteHeader, parse_iso_datetime, serialize_or_500,
to_handler_error,
};
use crate::service;
use manta_shared::types::api::configuration_analysis::ConfigurationAnalysis;
pub use manta_shared::types::api::queries::{
ConfigurationQuery, DeleteConfigurationsQuery,
};
#[utoipa::path(get, path = "/configurations", tag = "configurations",
params(ConfigurationQuery, SiteHeader),
security(("bearerAuth" = [])),
responses(
(status = 200, description = "Configurations with components-only safe_to_delete verdict",
body = Vec<ConfigurationAnalysis>),
(status = 401, description = "Unauthorized", body = ErrorResponse),
(status = 500, description = "Internal error", body = ErrorResponse),
)
)]
#[tracing::instrument(skip_all)]
pub async fn get_configurations(
ctx: RequestCtx,
Query(q): Query<ConfigurationQuery>,
) -> Result<impl IntoResponse, (StatusCode, Json<ErrorResponse>)> {
let infra = ctx.infra();
let params = service::configuration::GetConfigurationParams {
name: q.name,
pattern: q.pattern,
group_name: q.hsm_group,
settings_hsm_group_name: None,
since: None,
until: None,
limit: q.limit,
};
let rows = service::configuration::get_configurations_with_analysis(
&infra, &ctx.token, ¶ms,
)
.await
.map_err(to_handler_error)?;
Ok(Json(rows))
}
#[utoipa::path(delete, path = "/configurations", tag = "configurations",
params(DeleteConfigurationsQuery, SiteHeader),
security(("bearerAuth" = [])),
responses(
// dry_run/real result union — kept as Value until the union shape is formalised
(status = 200, description = "Configurations deleted or preview", body = serde_json::Value),
(status = 400, description = "Bad request", body = ErrorResponse),
(status = 401, description = "Unauthorized", body = ErrorResponse),
(status = 500, description = "Internal error", body = ErrorResponse),
)
)]
#[tracing::instrument(skip_all)]
pub async fn delete_configurations(
ctx: RequestCtx,
Query(q): Query<DeleteConfigurationsQuery>,
) -> Result<impl IntoResponse, (StatusCode, Json<ErrorResponse>)> {
tracing::info!("delete_configurations dry_run={}", q.dry_run);
let infra = ctx.infra();
let since = q
.since
.as_deref()
.map(|s| parse_iso_datetime("since", s))
.transpose()?;
let until = q
.until
.as_deref()
.map(|s| parse_iso_datetime("until", s))
.transpose()?;
let candidates = service::configuration::get_deletion_candidates(
&infra,
&ctx.token,
None,
q.pattern.as_deref(),
since,
until,
)
.await
.map_err(to_handler_error)?;
if q.dry_run {
return Ok((StatusCode::OK, Json(serialize_or_500(&candidates)?)));
}
service::configuration::delete_configurations_and_derivatives(
&infra,
&ctx.token,
&candidates,
)
.await
.map_err(to_handler_error)?;
Ok((
StatusCode::OK,
Json(serde_json::json!({
"deleted_configurations": candidates.configuration_names,
"deleted_images": candidates.image_ids,
})),
))
}