raisfast 0.2.23

The last backend you'll ever need. Rust-powered headless CMS with built-in blog, ecommerce, wallet, payment and 4 plugin engines.
use axum::Json;
use axum::extract::{Path, State};

use crate::dto::currencies::{CreateCurrencyRequest, CurrencyResponse, UpdateCurrencyRequest};
use crate::errors::app_error::AppError;
use crate::errors::response::ApiResponse;
use crate::errors::validation;
use crate::middleware::auth::AuthUser;
use crate::services::currencies as svc;

pub fn routes(
    registry: &mut crate::server::RouteRegistry,
    config: &crate::config::app::AppConfig,
) -> axum::Router<crate::AppState> {
    let restful = config.api_restful;
    let r = axum::Router::new();
    let r = reg_route!(
        r,
        registry,
        restful,
        "/admin/currencies",
        get,
        list_currencies,
        "system admin",
        "admin/currencies"
    );
    let r = reg_route!(
        r,
        registry,
        restful,
        "/admin/currencies",
        create,
        create_currency,
        "system admin",
        "admin/currencies"
    );
    let r = reg_route!(
        r,
        registry,
        restful,
        "/admin/currencies/{code}",
        get,
        get_currency,
        "system admin",
        "admin/currencies"
    );
    reg_route!(
        r,
        registry,
        restful,
        "/admin/currencies/{code}",
        put,
        update_currency,
        "system admin",
        "admin/currencies"
    )
}

#[utoipa::path(get, path = "/admin/currencies", tag = "currencies",
    security(("bearer_auth" = [])),
    responses((status = 200, description = "List currencies"))
)]
pub async fn list_currencies(
    auth: AuthUser,
    State(state): State<crate::AppState>,
) -> Result<ApiResponse<Vec<CurrencyResponse>>, AppError> {
    auth.ensure_admin()?;
    let rows = svc::list(&state.pool).await?;
    Ok(ApiResponse::success(
        rows.into_iter().map(CurrencyResponse::from).collect(),
    ))
}

#[utoipa::path(get, path = "/admin/currencies/{code}", tag = "currencies",
    security(("bearer_auth" = [])),
    params(("code" = String, Path, description = "Currency code")),
    responses((status = 200, description = "Currency detail"))
)]
pub async fn get_currency(
    auth: AuthUser,
    State(state): State<crate::AppState>,
    Path(code): Path<String>,
) -> Result<ApiResponse<CurrencyResponse>, AppError> {
    auth.ensure_admin()?;
    let c = svc::get_by_code(&state.pool, &code).await?;
    Ok(ApiResponse::success(CurrencyResponse::from(c)))
}

#[utoipa::path(post, path = "/admin/currencies", tag = "currencies",
    security(("bearer_auth" = [])),
    request_body = CreateCurrencyRequest,
    responses((status = 200, description = "Currency created"))
)]
pub async fn create_currency(
    auth: AuthUser,
    State(state): State<crate::AppState>,
    Json(req): Json<CreateCurrencyRequest>,
) -> Result<ApiResponse<CurrencyResponse>, AppError> {
    auth.ensure_admin()?;
    validation::validate(&req)?;
    let decimals = req.decimals.unwrap_or(2);
    let c = svc::create(&state.pool, &req.code, &req.name, decimals).await?;
    Ok(ApiResponse::success(CurrencyResponse::from(c)))
}

#[utoipa::path(put, path = "/admin/currencies/{code}", tag = "currencies",
    security(("bearer_auth" = [])),
    params(("code" = String, Path, description = "Currency code")),
    request_body = UpdateCurrencyRequest,
    responses((status = 200, description = "Currency updated"))
)]
pub async fn update_currency(
    auth: AuthUser,
    State(state): State<crate::AppState>,
    Path(code): Path<String>,
    Json(req): Json<UpdateCurrencyRequest>,
) -> Result<ApiResponse<CurrencyResponse>, AppError> {
    auth.ensure_admin()?;
    validation::validate(&req)?;
    svc::update(&state.pool, &code, req.name.as_deref(), req.is_active).await?;
    let c = svc::get_by_code(&state.pool, &code).await?;
    Ok(ApiResponse::success(CurrencyResponse::from(c)))
}