acme-proxy-admin 0.6.1

The operation layer and web admin panel of acme-proxy (internal crate, no semver promise)
Documentation
//! `/api/upstream-orders` — the relay signer's per-order upstream state,
//! read-only.
//!
//! There is no mutating route in this file and there is not meant to be one.
//! Abandoning an in-flight relay is done through `POST /api/jobs/{id}/cancel`
//! on the `signer_relay_issue` job, which owns the state machine. Neither
//! handler here takes
//! [`AuthenticatedWrite`](crate::webadmin::session::AuthenticatedWrite), and
//! `tests/admin_api.rs::mutating_endpoints()` has no entry for
//! `/api/upstream-orders`.

use axum::Json;
use axum::extract::{Path, Query, State};
use serde::Deserialize;
use serde_json::Value;

use crate::admin;
use crate::webadmin::AdminState;
use crate::webadmin::error::AdminError;
use crate::webadmin::handlers::paging::{PageParams, page_envelope};
use crate::webadmin::handlers::params::{bad_status, empty_is_absent};
use crate::webadmin::session::Authenticated;
use acme_proxy_store::status::UnknownStatus;
use acme_proxy_store::status::UpstreamOrderStatus;
use acme_proxy_store::upstream_order::UpstreamOrder;
use acme_proxy_store::upstream_order::UpstreamOrderQuery;

/// The window fields are inline, not `#[serde(flatten)]` — see the note on
/// [`super::accounts::AccountListParams`].
#[derive(Debug, Deserialize, Default)]
pub struct UpstreamOrderListParams {
    #[serde(default, deserialize_with = "empty_is_absent")]
    pub profile: Option<String>,
    #[serde(default, deserialize_with = "empty_is_absent")]
    pub status: Option<String>,
    pub limit: Option<i64>,
    pub offset: Option<i64>,
}

impl UpstreamOrderListParams {
    /// Refused by name so `/api` and `/ui` reject a bad `?status=` identically.
    pub fn parsed_status(&self) -> Result<Option<UpstreamOrderStatus>, UnknownStatus> {
        self.status.as_deref().map(str::parse).transpose()
    }
}

/// The listing query `params` asks for, refusals and all — shared with
/// `/ui/upstream-orders` (the [`super::orders::order_query`] rule).
pub(crate) fn upstream_order_query(
    params: &UpstreamOrderListParams,
    page: crate::webadmin::handlers::paging::Page,
) -> Result<UpstreamOrderQuery, AdminError> {
    Ok(UpstreamOrderQuery {
        profile: params.profile.clone(),
        status: params.parsed_status().map_err(bad_status)?,
        limit: page.limit,
        offset: page.offset,
    })
}

/// `GET /api/upstream-orders?profile=&status=&limit=&offset=`
pub async fn list_upstream_orders(
    State(state): State<AdminState>,
    Query(params): Query<UpstreamOrderListParams>,
    _auth: Authenticated,
) -> Result<Json<Value>, AdminError> {
    let page = PageParams::from(params.limit, params.offset).resolve(&state.config);
    let query = upstream_order_query(&params, page)?;
    let (rows, total) = UpstreamOrder::search(&query, &state.database).await?;
    let items = rows.iter().map(admin::render_upstream_order_json).collect();
    Ok(Json(page_envelope(items, total, page)))
}

/// `GET /api/upstream-orders/{id}` — by the **local** order id, cross-linked to
/// the relay job.
pub async fn get_upstream_order(
    State(state): State<AdminState>,
    Path(id): Path<String>,
    _auth: Authenticated,
) -> Result<Json<Value>, AdminError> {
    let detail = admin::load_upstream_order_detail(&id, state.database.clone())
        .await?
        .ok_or_else(|| AdminError::not_found(format!("no upstream order for local order {id}")))?;
    Ok(Json(admin::render_upstream_order_detail_json(&detail)))
}