manta_server/server/handlers/
image.rs

1//! GET/DELETE /api/v1/images.
2
3use axum::{Json, extract::Query, http::StatusCode, response::IntoResponse};
4
5use super::{ErrorResponse, RequestCtx, SiteHeader, to_handler_error};
6use crate::service;
7
8// ---------------------------------------------------------------------------
9// GET /api/v1/images
10// ---------------------------------------------------------------------------
11
12pub use manta_shared::types::api::queries::{DeleteImagesQuery, ImageQuery};
13
14/// GET /images — list IMS images sorted by creation time.
15#[utoipa::path(get, path = "/images", tag = "images",
16  params(ImageQuery, SiteHeader),
17  security(("bearerAuth" = [])),
18  responses(
19    (status = 200, description = "List of images", body = Vec<serde_json::Value>),
20    (status = 401, description = "Unauthorized",   body = ErrorResponse),
21    (status = 500, description = "Internal error", body = ErrorResponse),
22  )
23)]
24#[tracing::instrument(skip_all)]
25pub async fn get_images(
26  ctx: RequestCtx,
27  Query(q): Query<ImageQuery>,
28) -> Result<impl IntoResponse, (StatusCode, Json<ErrorResponse>)> {
29  let infra = ctx.infra();
30
31  let params = service::image::GetImagesParams {
32    id: q.id,
33    pattern: q.pattern,
34    limit: q.limit,
35  };
36
37  let images = service::image::get_images(&infra, &ctx.token, &params)
38    .await
39    .map_err(to_handler_error)?;
40
41  Ok(Json(images))
42}
43
44// ---------------------------------------------------------------------------
45// DELETE /api/v1/images — with ?ids=id1,id2&dry_run=true
46// ---------------------------------------------------------------------------
47
48/// `DELETE /api/v1/images` — delete IMS images by ID; validates only when `dry_run=true`.
49#[utoipa::path(delete, path = "/images", tag = "images",
50  params(DeleteImagesQuery, SiteHeader),
51  security(("bearerAuth" = [])),
52  responses(
53    // dry_run/real result union — kept as Value until the union shape is formalised
54    (status = 200, description = "Images deleted or validation result", body = serde_json::Value),
55    (status = 400, description = "Bad request",                         body = ErrorResponse),
56    (status = 401, description = "Unauthorized",                        body = ErrorResponse),
57    (status = 500, description = "Internal error",                      body = ErrorResponse),
58  )
59)]
60#[tracing::instrument(skip_all)]
61pub async fn delete_images(
62  ctx: RequestCtx,
63  Query(q): Query<DeleteImagesQuery>,
64) -> Result<impl IntoResponse, (StatusCode, Json<ErrorResponse>)> {
65  tracing::info!("delete_images ids={} dry_run={}", q.ids, q.dry_run);
66  let infra = ctx.infra();
67
68  let id_strings: Vec<String> =
69    q.ids.split(',').map(|s| s.trim().to_string()).collect();
70  let id_refs: Vec<&str> =
71    id_strings.iter().map(std::string::String::as_str).collect();
72
73  if q.dry_run {
74    service::image::validate_image_deletion(&infra, &ctx.token, &id_refs, None)
75      .await
76      .map_err(to_handler_error)?;
77    return Ok((
78      StatusCode::OK,
79      Json(serde_json::json!({ "validated_ids": id_strings })),
80    ));
81  }
82
83  let deleted =
84    service::image::delete_images(&infra, &ctx.token, &id_refs, None)
85      .await
86      .map_err(to_handler_error)?;
87
88  Ok((
89    StatusCode::OK,
90    Json(serde_json::json!({ "deleted": deleted })),
91  ))
92}