Skip to main content

postrust_proxy/saas/handlers/
routes.rs

1//! Domain route API handlers.
2
3use crate::admin::api::ApiResponse;
4use crate::saas::auth::Auth;
5use crate::saas::handlers::{error_response, SaasState};
6use crate::saas::types::{CreateDomainRouteRequest, UpdateDomainRouteRequest};
7use axum::{
8    extract::{Path, State},
9    http::StatusCode,
10    response::IntoResponse,
11    Json,
12};
13use uuid::Uuid;
14
15/// List routes for a domain.
16pub async fn list_routes(
17    State(state): State<SaasState>,
18    Auth(auth): Auth,
19    Path(domain_id): Path<Uuid>,
20) -> impl IntoResponse {
21    match state
22        .domain_manager
23        .list_routes_for_domain(domain_id, auth.tenant_id)
24        .await
25    {
26        Ok(routes) => Json(ApiResponse::success(routes)).into_response(),
27        Err(e) => error_response(e).into_response(),
28    }
29}
30
31/// Create a new route for a domain.
32pub async fn create_route(
33    State(state): State<SaasState>,
34    Auth(auth): Auth,
35    Path(domain_id): Path<Uuid>,
36    Json(req): Json<CreateDomainRouteRequest>,
37) -> impl IntoResponse {
38    if !auth.can_write("routes") {
39        return (
40            StatusCode::FORBIDDEN,
41            Json(ApiResponse::<()>::error("Insufficient permissions")),
42        )
43            .into_response();
44    }
45
46    match state
47        .domain_manager
48        .create_route(domain_id, auth.tenant_id, req)
49        .await
50    {
51        Ok(route) => (StatusCode::CREATED, Json(ApiResponse::success(route))).into_response(),
52        Err(e) => error_response(e).into_response(),
53    }
54}
55
56/// Get a route by ID.
57pub async fn get_route(
58    State(state): State<SaasState>,
59    Auth(auth): Auth,
60    Path((domain_id, id)): Path<(Uuid, Uuid)>,
61) -> impl IntoResponse {
62    match state.domain_manager.get_route(id, auth.tenant_id).await {
63        Ok(Some(route)) => {
64            // Verify route belongs to the specified domain
65            if route.domain_id != domain_id {
66                return (
67                    StatusCode::NOT_FOUND,
68                    Json(ApiResponse::<()>::error("Route not found")),
69                )
70                    .into_response();
71            }
72            Json(ApiResponse::success(route)).into_response()
73        }
74        Ok(None) => (
75            StatusCode::NOT_FOUND,
76            Json(ApiResponse::<()>::error("Route not found")),
77        )
78            .into_response(),
79        Err(e) => error_response(e).into_response(),
80    }
81}
82
83/// Update a route.
84pub async fn update_route(
85    State(state): State<SaasState>,
86    Auth(auth): Auth,
87    Path((domain_id, id)): Path<(Uuid, Uuid)>,
88    Json(req): Json<UpdateDomainRouteRequest>,
89) -> impl IntoResponse {
90    if !auth.can_write("routes") {
91        return (
92            StatusCode::FORBIDDEN,
93            Json(ApiResponse::<()>::error("Insufficient permissions")),
94        )
95            .into_response();
96    }
97
98    // First check if route exists and belongs to the domain
99    match state.domain_manager.get_route(id, auth.tenant_id).await {
100        Ok(Some(route)) => {
101            if route.domain_id != domain_id {
102                return (
103                    StatusCode::NOT_FOUND,
104                    Json(ApiResponse::<()>::error("Route not found")),
105                )
106                    .into_response();
107            }
108        }
109        Ok(None) => {
110            return (
111                StatusCode::NOT_FOUND,
112                Json(ApiResponse::<()>::error("Route not found")),
113            )
114                .into_response();
115        }
116        Err(e) => return error_response(e).into_response(),
117    }
118
119    match state
120        .domain_manager
121        .update_route(id, auth.tenant_id, req)
122        .await
123    {
124        Ok(Some(route)) => Json(ApiResponse::success(route)).into_response(),
125        Ok(None) => (
126            StatusCode::NOT_FOUND,
127            Json(ApiResponse::<()>::error("Route not found")),
128        )
129            .into_response(),
130        Err(e) => error_response(e).into_response(),
131    }
132}
133
134/// Delete a route.
135pub async fn delete_route(
136    State(state): State<SaasState>,
137    Auth(auth): Auth,
138    Path((domain_id, id)): Path<(Uuid, Uuid)>,
139) -> impl IntoResponse {
140    if !auth.can_write("routes") {
141        return (
142            StatusCode::FORBIDDEN,
143            Json(ApiResponse::<()>::error("Insufficient permissions")),
144        )
145            .into_response();
146    }
147
148    // First check if route exists and belongs to the domain
149    match state.domain_manager.get_route(id, auth.tenant_id).await {
150        Ok(Some(route)) => {
151            if route.domain_id != domain_id {
152                return (
153                    StatusCode::NOT_FOUND,
154                    Json(ApiResponse::<()>::error("Route not found")),
155                )
156                    .into_response();
157            }
158        }
159        Ok(None) => {
160            return (
161                StatusCode::NOT_FOUND,
162                Json(ApiResponse::<()>::error("Route not found")),
163            )
164                .into_response();
165        }
166        Err(e) => return error_response(e).into_response(),
167    }
168
169    match state.domain_manager.delete_route(id, auth.tenant_id).await {
170        Ok(true) => Json(ApiResponse::success(())).into_response(),
171        Ok(false) => (
172            StatusCode::NOT_FOUND,
173            Json(ApiResponse::<()>::error("Route not found")),
174        )
175            .into_response(),
176        Err(e) => error_response(e).into_response(),
177    }
178}