diff --git a/crates/api_models/src/admin.rs b/crates/api_models/src/admin.rs index 0bce39782a..a7f91bae6d 100644 --- a/crates/api_models/src/admin.rs +++ b/crates/api_models/src/admin.rs @@ -340,3 +340,20 @@ pub struct DeleteMcaResponse { #[schema(example = false)] pub deleted: bool, } + +#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] +pub struct ToggleKVResponse { + /// The identifier for the Merchant Account + #[schema(max_length = 255, example = "y3oqhf46pyzuxjbcn2giaqnb44")] + pub merchant_id: String, + /// Status of KV for the specific merchant + #[schema(example = true)] + pub kv_enabled: bool, +} + +#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] +pub struct ToggleKVRequest { + /// Status of KV for the specific merchant + #[schema(example = true)] + pub kv_enabled: bool, +} diff --git a/crates/router/src/core/admin.rs b/crates/router/src/core/admin.rs index ffe9fdb937..fcaf3860ca 100644 --- a/crates/router/src/core/admin.rs +++ b/crates/router/src/core/admin.rs @@ -1,5 +1,6 @@ use common_utils::ext_traits::ValueExt; use error_stack::{report, FutureExt, ResultExt}; +use storage_models::{enums, merchant_account}; use uuid::Uuid; use crate::{ @@ -464,3 +465,81 @@ pub async fn delete_payment_connector( }; Ok(service_api::ApplicationResponse::Json(response)) } + +pub async fn kv_for_merchant( + db: &dyn StorageInterface, + merchant_id: String, + enable: bool, +) -> RouterResponse { + // check if the merchant account exists + let merchant_account = db + .find_merchant_account_by_merchant_id(&merchant_id) + .await + .map_err(|error| { + error.to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound) + })?; + + let updated_merchant_account = match (enable, merchant_account.storage_scheme) { + (true, enums::MerchantStorageScheme::RedisKv) + | (false, enums::MerchantStorageScheme::PostgresOnly) => Ok(merchant_account), + (true, enums::MerchantStorageScheme::PostgresOnly) => { + db.update_merchant( + merchant_account, + merchant_account::MerchantAccountUpdate::StorageSchemeUpdate { + storage_scheme: enums::MerchantStorageScheme::RedisKv, + }, + ) + .await + } + (false, enums::MerchantStorageScheme::RedisKv) => { + db.update_merchant( + merchant_account, + merchant_account::MerchantAccountUpdate::StorageSchemeUpdate { + storage_scheme: enums::MerchantStorageScheme::PostgresOnly, + }, + ) + .await + } + } + .map_err(|error| { + error + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("failed to switch merchant_storage_scheme") + })?; + let kv_status = matches!( + updated_merchant_account.storage_scheme, + enums::MerchantStorageScheme::RedisKv + ); + + Ok(service_api::ApplicationResponse::Json( + api_models::admin::ToggleKVResponse { + merchant_id: updated_merchant_account.merchant_id, + kv_enabled: kv_status, + }, + )) +} + +pub async fn check_merchant_account_kv_status( + db: &dyn StorageInterface, + merchant_id: String, +) -> RouterResponse { + // check if the merchant account exists + let merchant_account = db + .find_merchant_account_by_merchant_id(&merchant_id) + .await + .map_err(|error| { + error.to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound) + })?; + + let kv_status = matches!( + merchant_account.storage_scheme, + enums::MerchantStorageScheme::RedisKv + ); + + Ok(service_api::ApplicationResponse::Json( + api_models::admin::ToggleKVResponse { + merchant_id: merchant_account.merchant_id, + kv_enabled: kv_status, + }, + )) +} diff --git a/crates/router/src/routes/admin.rs b/crates/router/src/routes/admin.rs index f44642f3b6..6cab7d6944 100644 --- a/crates/router/src/routes/admin.rs +++ b/crates/router/src/routes/admin.rs @@ -337,3 +337,49 @@ pub async fn payment_connector_delete( ) .await } + +// Merchant Account - Toggle KV + +/// +/// Toggle KV mode for the Merchant Account +#[instrument(skip_all)] +pub async fn merchant_account_toggle_kv( + state: web::Data, + req: HttpRequest, + path: web::Path, + json_payload: web::Json, +) -> HttpResponse { + let payload = json_payload.into_inner(); + let merchant_id = path.into_inner(); + api::server_wrap( + state.get_ref(), + &req, + (merchant_id, payload), + |state, _, (merchant_id, payload)| { + kv_for_merchant(&*state.store, merchant_id, payload.kv_enabled) + }, + &auth::AdminApiAuth, + ) + .await +} + +// Merchant Account - KV Status + +/// +/// Toggle KV mode for the Merchant Account +#[instrument(skip_all)] +pub async fn merchant_account_kv_status( + state: web::Data, + req: HttpRequest, + path: web::Path, +) -> HttpResponse { + let merchant_id = path.into_inner(); + api::server_wrap( + state.get_ref(), + &req, + merchant_id, + |state, _, req| check_merchant_account_kv_status(&*state.store, req), + &auth::AdminApiAuth, + ) + .await +} diff --git a/crates/router/src/routes/app.rs b/crates/router/src/routes/app.rs index 8089d9c969..0d13846b6a 100644 --- a/crates/router/src/routes/app.rs +++ b/crates/router/src/routes/app.rs @@ -226,6 +226,11 @@ impl MerchantAccount { web::scope("/accounts") .app_data(web::Data::new(state)) .service(web::resource("").route(web::post().to(merchant_account_create))) + .service( + web::resource("/{id}/kv") + .route(web::post().to(merchant_account_toggle_kv)) + .route(web::get().to(merchant_account_kv_status)), + ) .service( web::resource("/{id}") .route(web::get().to(retrieve_merchant_account)) diff --git a/crates/router/src/types/api/admin.rs b/crates/router/src/types/api/admin.rs index b9fd8de43b..f06dc4623d 100644 --- a/crates/router/src/types/api/admin.rs +++ b/crates/router/src/types/api/admin.rs @@ -1,7 +1,8 @@ pub use api_models::admin::{ CreateMerchantAccount, DeleteMcaResponse, DeleteMerchantAccountResponse, MerchantAccountResponse, MerchantConnectorId, MerchantDetails, MerchantId, - PaymentConnectorCreate, PaymentMethods, RoutingAlgorithm, WebhookDetails, + PaymentConnectorCreate, PaymentMethods, RoutingAlgorithm, ToggleKVRequest, ToggleKVResponse, + WebhookDetails, }; use crate::types::{storage, transformers::Foreign}; diff --git a/crates/storage_models/src/merchant_account.rs b/crates/storage_models/src/merchant_account.rs index 38f8a5bae5..e7d53cbd21 100644 --- a/crates/storage_models/src/merchant_account.rs +++ b/crates/storage_models/src/merchant_account.rs @@ -73,6 +73,9 @@ pub enum MerchantAccountUpdate { metadata: Option, routing_algorithm: Option, }, + StorageSchemeUpdate { + storage_scheme: storage_enums::MerchantStorageScheme, + }, } #[derive(Clone, Debug, Default, AsChangeset, router_derive::DebugAsDisplay)] @@ -89,6 +92,7 @@ pub struct MerchantAccountUpdateInternal { payment_response_hash_key: Option, redirect_to_merchant_with_http_post: Option, publishable_key: Option, + storage_scheme: Option, locker_id: Option, metadata: Option, routing_algorithm: Option, @@ -127,6 +131,11 @@ impl From for MerchantAccountUpdateInternal { publishable_key, locker_id, metadata, + ..Default::default() + }, + MerchantAccountUpdate::StorageSchemeUpdate { storage_scheme } => Self { + storage_scheme: Some(storage_scheme), + ..Default::default() }, } }