manta_server/server/handlers/
image.rs1use axum::{Json, extract::Query, http::StatusCode, response::IntoResponse};
4use serde::{Deserialize, Serialize};
5use utoipa::{IntoParams, ToSchema};
6
7use super::{
8 ErrorResponse, RequestCtx, SiteHeader, serialize_or_500, to_handler_error,
9};
10use crate::service;
11
12#[derive(Deserialize, IntoParams)]
18pub struct ImageQuery {
19 pub id: Option<String>,
21 pub hsm_group: Option<String>,
23 pub limit: Option<u8>,
25}
26
27#[derive(Serialize, ToSchema)]
29pub struct ImageEntry {
30 pub image: serde_json::Value,
32 pub configuration_name: String,
34 pub image_id: String,
37 pub is_linked: bool,
40}
41
42#[utoipa::path(get, path = "/images", tag = "images",
44 params(ImageQuery, SiteHeader),
45 security(("bearerAuth" = [])),
46 responses(
47 (status = 200, description = "List of images", body = Vec<ImageEntry>),
48 (status = 401, description = "Unauthorized", body = ErrorResponse),
49 (status = 500, description = "Internal error", body = ErrorResponse),
50 )
51)]
52#[tracing::instrument(skip_all)]
53pub async fn get_images(
54 ctx: RequestCtx,
55 Query(q): Query<ImageQuery>,
56) -> Result<impl IntoResponse, (StatusCode, Json<ErrorResponse>)> {
57 let infra = ctx.infra();
58
59 let params = service::image::GetImagesParams {
60 id: q.id,
61 hsm_group: q.hsm_group,
62 settings_hsm_group_name: None,
63 limit: q.limit,
64 };
65
66 let images = service::image::get_images(&infra, &ctx.token, ¶ms)
67 .await
68 .map_err(to_handler_error)?;
69
70 let mut entries = Vec::with_capacity(images.len());
71 for (img, config_name, image_id, linked) in images {
72 let image = serialize_or_500(&img)?;
73 entries.push(ImageEntry {
74 image,
75 configuration_name: config_name,
76 image_id,
77 is_linked: linked,
78 });
79 }
80
81 Ok(Json(entries))
82}
83
84#[derive(Deserialize, IntoParams)]
90pub struct DeleteImagesQuery {
91 pub ids: String,
93 #[serde(default)]
95 pub dry_run: bool,
96}
97
98#[utoipa::path(delete, path = "/images", tag = "images",
100 params(DeleteImagesQuery, SiteHeader),
101 security(("bearerAuth" = [])),
102 responses(
103 (status = 200, description = "Images deleted or validation result", body = serde_json::Value),
104 (status = 400, description = "Bad request", body = ErrorResponse),
105 (status = 401, description = "Unauthorized", body = ErrorResponse),
106 (status = 500, description = "Internal error", body = ErrorResponse),
107 )
108)]
109#[tracing::instrument(skip_all)]
110pub async fn delete_images(
111 ctx: RequestCtx,
112 Query(q): Query<DeleteImagesQuery>,
113) -> Result<impl IntoResponse, (StatusCode, Json<ErrorResponse>)> {
114 tracing::info!("delete_images ids={} dry_run={}", q.ids, q.dry_run);
115 let infra = ctx.infra();
116
117 let id_strings: Vec<String> =
118 q.ids.split(',').map(|s| s.trim().to_string()).collect();
119 let id_refs: Vec<&str> =
120 id_strings.iter().map(std::string::String::as_str).collect();
121
122 if q.dry_run {
123 service::image::validate_image_deletion(&infra, &ctx.token, &id_refs, None)
124 .await
125 .map_err(to_handler_error)?;
126 return Ok((
127 StatusCode::OK,
128 Json(serde_json::json!({ "validated_ids": id_strings })),
129 ));
130 }
131
132 let deleted =
133 service::image::delete_images(&infra, &ctx.token, &id_refs, None)
134 .await
135 .map_err(to_handler_error)?;
136
137 Ok((
138 StatusCode::OK,
139 Json(serde_json::json!({ "deleted": deleted })),
140 ))
141}