zlicenser_server/http/
mod.rs1pub mod enroll;
2pub mod revoke;
3pub mod transfer;
4pub mod upgrade;
5pub mod webhook;
6
7use std::sync::Arc;
8
9use axum::{
10 Json, Router,
11 http::StatusCode,
12 response::{IntoResponse, Response},
13 routing::{delete, post},
14};
15use serde_json::json;
16
17use crate::issuance::handlers::HandlerContext;
18use crate::storage::Storage;
19
20pub fn build_router<S: Storage + Clone + Send + Sync + 'static>(
21 ctx: Arc<HandlerContext<S>>,
22) -> Router {
23 Router::new()
24 .route("/enroll/request", post(enroll::request_handler::<S>))
25 .route(
26 "/enroll/receipt/{session_id}",
27 post(enroll::receipt_handler::<S>),
28 )
29 .route("/webhook/stripe", post(webhook::stripe_handler::<S>))
30 .route("/licenses/{id}", delete(revoke::revoke_handler::<S>))
31 .route(
32 "/licenses/{id}/transfer/request",
33 post(transfer::request_handler::<S>),
34 )
35 .route(
36 "/transfers/{id}/approve",
37 post(transfer::approve_handler::<S>),
38 )
39 .route(
40 "/transfers/{id}/reject",
41 post(transfer::reject_handler::<S>),
42 )
43 .route(
44 "/licenses/{id}/upgrade",
45 post(upgrade::upgrade_handler::<S>),
46 )
47 .with_state(ctx)
48}
49
50impl IntoResponse for crate::Error {
51 fn into_response(self) -> Response {
52 let (status, code) = match &self {
53 crate::Error::NotFound
54 | crate::Error::SessionNotFound
55 | crate::Error::BindingNotFound => (StatusCode::NOT_FOUND, "not_found"),
56
57 crate::Error::OfferExpired => (StatusCode::GONE, "offer_expired"),
58
59 crate::Error::SeatLimitReached
60 | crate::Error::Conflict(_)
61 | crate::Error::TransferAlreadyPending => (StatusCode::CONFLICT, "conflict"),
62
63 crate::Error::InvalidTransition(_) => (StatusCode::CONFLICT, "invalid_transition"),
64
65 crate::Error::PaymentNotHeld => (StatusCode::PAYMENT_REQUIRED, "payment_not_held"),
66
67 crate::Error::TsaFailed(_) | crate::Error::PaymentCaptureFailed(_) => {
68 (StatusCode::BAD_GATEWAY, "upstream_failure")
69 }
70
71 crate::Error::ClientVersionRejected { .. }
72 | crate::Error::OfferNonceMismatch
73 | crate::Error::InvalidReceiptSignature
74 | crate::Error::ConsentInvalid(_) => (StatusCode::BAD_REQUEST, "bad_request"),
75
76 crate::Error::ProductInactive
77 | crate::Error::RevocationNotSupported
78 | crate::Error::ForeignKeyViolation(_) => {
79 (StatusCode::UNPROCESSABLE_ENTITY, "rejected")
80 }
81
82 _ => (StatusCode::INTERNAL_SERVER_ERROR, "internal_error"),
83 };
84
85 let body = Json(json!({ "error": code, "message": self.to_string() }));
86 (status, body).into_response()
87 }
88}