Skip to main content

acme_proxy_admin/webadmin/handlers/
mod.rs

1//! One module per admin resource, re-exported flat — mirroring
2//! [`acme_proxy_protocol::handlers`], which does the same for the ACME resources.
3//!
4//! Every handler here is a few lines over [`crate::admin::ops`] and
5//! [`crate::admin::render`]: this layer decides status codes and shapes,
6//! nothing more.
7//!
8//! ## One write, one function, both front ends
9//!
10//! Every mutating action lives once, as a `pub(crate) async fn apply_*` beside
11//! its `/api` handler, and the `/ui` page calls the same function. It owns
12//! everything the action owes: the validation, the write, every audit row and
13//! the `admin_*` log line. The two front ends keep only what really differs:
14//! extracting a JSON body or a form, and answering with a status and JSON or a
15//! fragment and a banner. [`Caller`] carries who acted and through which
16//! surface.
17//!
18//! Spelled out twice, the two copies drifted: one surface logged an action the
19//! other did not, or logged it without its `surface` field. **No `#[instrument]`** anywhere in it — the access middleware
20//! already opens the request span, and the attribute moves a handler body into
21//! a generated async block that reports almost no coverage (see the book's
22//! Testing & Coverage page).
23
24pub mod account;
25pub mod accounts;
26pub mod audit;
27pub mod eab;
28pub mod expiring;
29pub mod filter;
30pub mod jobs;
31pub mod mfa;
32pub mod misc;
33pub mod operators;
34pub mod orders;
35pub mod paging;
36pub mod params;
37pub mod session;
38pub mod upstream_orders;
39
40pub use account::*;
41pub use accounts::*;
42pub use audit::*;
43pub use eab::*;
44pub use expiring::*;
45pub use filter::*;
46pub use jobs::*;
47pub use mfa::*;
48pub use misc::*;
49pub use operators::*;
50pub use orders::*;
51pub use session::*;
52pub use upstream_orders::*;
53
54use crate::webadmin::session::Authenticated;
55use acme_proxy_core::audit::RequestContext;
56
57/// Who is performing a write, and through which front end.
58///
59/// Every `apply_*` action takes one. The operator names the audit row and the
60/// log line, the request context resolves the client address the row records,
61/// and `surface` is the one field the two front ends' log lines differ by.
62pub(crate) struct Caller<'a> {
63    pub(crate) auth: &'a Authenticated,
64    pub(crate) request: &'a RequestContext,
65    pub(crate) surface: &'static str,
66}
67
68impl<'a> Caller<'a> {
69    /// A write through `/api`.
70    pub(crate) fn api(auth: &'a Authenticated, request: &'a RequestContext) -> Self {
71        Self {
72            auth,
73            request,
74            surface: "api",
75        }
76    }
77
78    /// A write through `/ui`.
79    pub(crate) fn ui(auth: &'a Authenticated, request: &'a RequestContext) -> Self {
80        Self {
81            auth,
82            request,
83            surface: "ui",
84        }
85    }
86
87    /// The operator's username, which attributes the row and the log line.
88    pub(crate) fn username(&self) -> &str {
89        &self.auth.user.username
90    }
91}