ironflow_api/routes/secrets/
list.rs1use axum::extract::{Query, State};
4use axum::response::IntoResponse;
5use serde::Deserialize;
6
7use ironflow_auth::extractor::Authenticated;
8
9use crate::entities::SecretResponse;
10use crate::error::ApiError;
11use crate::response::ok_paged;
12use crate::state::AppState;
13
14#[cfg_attr(feature = "openapi", derive(utoipa::IntoParams))]
16#[derive(Debug, Deserialize)]
17pub struct ListSecretsQuery {
18 pub prefix: Option<String>,
20 pub page: Option<u32>,
22 pub per_page: Option<u32>,
24}
25
26#[cfg_attr(
30 feature = "openapi",
31 utoipa::path(
32 get,
33 path = "/api/v1/secrets",
34 tags = ["secrets"],
35 params(ListSecretsQuery),
36 responses(
37 (status = 200, description = "Secrets listed", body = Vec<SecretResponse>),
38 (status = 401, description = "Unauthorized"),
39 (status = 403, description = "Forbidden")
40 ),
41 security(("Bearer" = []))
42 )
43)]
44pub async fn list_secrets(
45 auth: Authenticated,
46 State(state): State<AppState>,
47 Query(query): Query<ListSecretsQuery>,
48) -> Result<impl IntoResponse, ApiError> {
49 if !auth.is_admin() {
50 return Err(ApiError::Forbidden);
51 }
52
53 let prefix = query.prefix.as_deref().unwrap_or("");
54 let page = query.page.unwrap_or(1).max(1);
55 let per_page = query.per_page.unwrap_or(50).clamp(1, 100);
56
57 let result = state.store.list_secrets(prefix, page, per_page).await?;
58
59 let data: Vec<SecretResponse> = result.items.into_iter().map(SecretResponse::from).collect();
60
61 Ok(ok_paged(data, result.page, result.per_page, result.total))
62}