use std::sync::Arc; use axum::{ Json, extract::{Path, State}, http::StatusCode, response::IntoResponse, }; use serde::{Deserialize, Serialize}; use uuid::Uuid; use crate::routes::api::{AppError, ApiRouter}; use crate::service::proxy::access_rule::{ AccessRuleService, CreateAccessRuleParams, UpdateAccessRuleParams, }; use crate::service::proxy::types::AccessRuleConfig; #[derive(Serialize)] pub(crate) struct AccessRuleResponse { pub id: Uuid, pub r#type: String, pub ip_cidr: String, pub description: Option, pub priority: i32, pub override_of_id: Option, } impl From for AccessRuleResponse { fn from(c: AccessRuleConfig) -> Self { Self { id: c.id, r#type: c.r#type, ip_cidr: c.ip_cidr, description: c.description, priority: c.priority, override_of_id: c.override_of_id, } } } #[derive(Deserialize)] pub(crate) struct CreateAccessRuleRequest { pub server_id: Option, pub location_id: Option, pub r#type: String, pub ip_cidr: String, pub description: Option, pub priority: i32, pub override_of_id: Option, } impl From for CreateAccessRuleParams { fn from(r: CreateAccessRuleRequest) -> Self { Self { server_id: r.server_id, location_id: r.location_id, r#type: r.r#type, ip_cidr: r.ip_cidr, description: r.description, priority: r.priority, override_of_id: r.override_of_id, } } } #[derive(Deserialize)] pub(crate) struct UpdateAccessRuleRequest { pub server_id: Option>, pub location_id: Option>, pub r#type: Option, pub ip_cidr: Option, pub description: Option>, pub priority: Option, pub override_of_id: Option>, } impl From for UpdateAccessRuleParams { fn from(r: UpdateAccessRuleRequest) -> Self { Self { server_id: r.server_id, location_id: r.location_id, r#type: r.r#type, ip_cidr: r.ip_cidr, description: r.description, priority: r.priority, override_of_id: r.override_of_id, } } } async fn list_access_rules_by_server( State(svc): State>, Path(server_id): Path, ) -> Result>, AppError> { let rules = svc.list_by_server(server_id).await?; Ok(Json(rules.into_iter().map(Into::into).collect())) } async fn list_access_rules_by_location( State(svc): State>, Path(location_id): Path, ) -> Result>, AppError> { let rules = svc.list_by_location(location_id).await?; Ok(Json(rules.into_iter().map(Into::into).collect())) } async fn create_access_rule( State(svc): State>, Json(body): Json, ) -> Result { let rule = svc.create(body.into()).await?; Ok((StatusCode::CREATED, Json(AccessRuleResponse::from(rule)))) } async fn get_access_rule( State(svc): State>, Path(id): Path, ) -> Result, AppError> { let rule = svc.get(id).await?; Ok(Json(rule.into())) } async fn update_access_rule( State(svc): State>, Path(id): Path, Json(body): Json, ) -> Result, AppError> { let rule = svc.update(id, body.into()).await?; Ok(Json(rule.into())) } async fn delete_access_rule( State(svc): State>, Path(id): Path, ) -> Result { let deleted = svc.delete(id).await?; if deleted { Ok((StatusCode::NO_CONTENT,)) } else { Err(AppError::NotFound) } } pub(super) fn routes() -> ApiRouter { ApiRouter::new() .route( "/server-blocks/{server_id}/access-rules", axum::routing::get(list_access_rules_by_server), ) .route( "/locations/{location_id}/access-rules", axum::routing::get(list_access_rules_by_location), ) .route( "/access-rules", axum::routing::post(create_access_rule), ) .route( "/access-rules/{id}", axum::routing::get(get_access_rule) .put(update_access_rule) .delete(delete_access_rule), ) }