Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions crates/api_models/src/events.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub mod customer;
pub mod gsm;
pub mod payment;
#[cfg(feature = "payouts")]
pub mod payouts;
Expand Down
33 changes: 33 additions & 0 deletions crates/api_models/src/events/gsm.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
use common_utils::events::{ApiEventMetric, ApiEventsType};

use crate::gsm;

impl ApiEventMetric for gsm::GsmCreateRequest {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::Gsm)
}
}

impl ApiEventMetric for gsm::GsmUpdateRequest {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::Gsm)
}
}

impl ApiEventMetric for gsm::GsmRetrieveRequest {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::Gsm)
}
}

impl ApiEventMetric for gsm::GsmDeleteRequest {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::Gsm)
}
}

impl ApiEventMetric for gsm::GsmDeleteResponse {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::Gsm)
}
}
75 changes: 75 additions & 0 deletions crates/api_models/src/gsm.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
use crate::enums;

#[derive(Debug, serde::Deserialize, serde::Serialize)]
pub struct GsmCreateRequest {
pub connector: enums::Connector,
pub flow: String,
pub sub_flow: String,
pub code: String,
pub message: String,
pub status: String,
pub router_error: Option<String>,
pub decision: GsmDecision,
pub step_up_possible: bool,
}

#[derive(Debug, serde::Deserialize, serde::Serialize)]
pub struct GsmRetrieveRequest {
pub connector: enums::Connector,
pub flow: String,
pub sub_flow: String,
pub code: String,
pub message: String,
}

#[derive(
Default,
Clone,
Copy,
Debug,
strum::Display,
PartialEq,
Eq,
serde::Serialize,
serde::Deserialize,
strum::EnumString,
)]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum GsmDecision {
Retry,
Requeue,
#[default]
DoDefault,
}

#[derive(Debug, serde::Deserialize, serde::Serialize)]
pub struct GsmUpdateRequest {
pub connector: String,
pub flow: String,
pub sub_flow: String,
pub code: String,
pub message: String,
pub status: Option<String>,
pub router_error: Option<String>,
pub decision: Option<GsmDecision>,
pub step_up_possible: Option<bool>,
}

#[derive(Debug, serde::Deserialize, serde::Serialize)]
pub struct GsmDeleteRequest {
pub connector: String,
pub flow: String,
pub sub_flow: String,
pub code: String,
pub message: String,
}

#[derive(Debug, serde::Serialize)]
pub struct GsmDeleteResponse {
pub gsm_rule_delete: bool,
pub connector: String,
pub flow: String,
pub sub_flow: String,
pub code: String,
}
1 change: 1 addition & 0 deletions crates/api_models/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub mod ephemeral_key;
pub mod errors;
pub mod events;
pub mod files;
pub mod gsm;
pub mod mandates;
pub mod organization;
pub mod payment_methods;
Expand Down
1 change: 1 addition & 0 deletions crates/common_utils/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ pub enum ApiEventsType {
Routing,
ResourceListAPI,
PaymentRedirectionResponse,
Gsm,
// TODO: This has to be removed once the corresponding apiEventTypes are created
Miscellaneous,
}
Expand Down
11 changes: 10 additions & 1 deletion crates/diesel_models/src/gsm.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
//! Gateway status mapping

use common_utils::custom_serde;
use common_utils::{
custom_serde,
events::{ApiEventMetric, ApiEventsType},
};
use diesel::{AsChangeset, Identifiable, Insertable, Queryable};
use time::PrimitiveDateTime;

Expand Down Expand Up @@ -95,3 +98,9 @@ impl From<GatewayStatusMappingUpdate> for GatewayStatusMapperUpdateInternal {
}
}
}

impl ApiEventMetric for GatewayStatusMap {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::Gsm)
}
}
1 change: 1 addition & 0 deletions crates/router/src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ pub mod customers;
pub mod disputes;
pub mod errors;
pub mod files;
pub mod gsm;
pub mod mandate;
pub mod metrics;
pub mod payment_link;
Expand Down
137 changes: 137 additions & 0 deletions crates/router/src/core/gsm.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
use api_models::gsm as gsm_api_types;
use diesel_models::gsm as storage;
use error_stack::{IntoReport, ResultExt};
use router_env::{instrument, tracing};

use crate::{
core::{
errors,
errors::{RouterResponse, StorageErrorExt},
},
db::gsm::GsmInterface,
services,
types::{self, transformers::ForeignInto},
AppState,
};

#[instrument(skip_all)]
pub async fn create_gsm_rule(
state: AppState,
gsm_rule: gsm_api_types::GsmCreateRequest,
) -> RouterResponse<types::GsmResponse> {
let db = state.store.as_ref();
GsmInterface::add_gsm_rule(db, gsm_rule.foreign_into())
.await
.to_duplicate_response(errors::ApiErrorResponse::GenericDuplicateError {
message: "GSM with given key already exists in our records".to_string(),
})
.map(services::ApplicationResponse::Json)
}

#[instrument(skip_all)]
pub async fn retrieve_gsm_rule(
state: AppState,
gsm_request: gsm_api_types::GsmRetrieveRequest,
) -> RouterResponse<types::GsmResponse> {
let db = state.store.as_ref();
let gsm_api_types::GsmRetrieveRequest {
connector,
flow,
sub_flow,
code,
message,
} = gsm_request;
GsmInterface::find_gsm_rule(db, connector.to_string(), flow, sub_flow, code, message)
.await
.to_not_found_response(errors::ApiErrorResponse::GenericNotFoundError {
message: "GSM with given key does not exist in our records".to_string(),
})
.map(services::ApplicationResponse::Json)
}

#[instrument(skip_all)]
pub async fn update_gsm_rule(
state: AppState,
gsm_request: gsm_api_types::GsmUpdateRequest,
) -> RouterResponse<types::GsmResponse> {
let db = state.store.as_ref();
let gsm_api_types::GsmUpdateRequest {
connector,
flow,
sub_flow,
code,
message,
decision,
status,
router_error,
step_up_possible,
} = gsm_request;
GsmInterface::update_gsm_rule(
db,
connector.to_string(),
flow,
sub_flow,
code,
message,
storage::GatewayStatusMappingUpdate {
decision: decision.map(|d| d.to_string()),
status,
router_error: Some(router_error),
step_up_possible,
},
)
.await
.to_not_found_response(errors::ApiErrorResponse::GenericNotFoundError {
message: "GSM with given key does not exist in our records".to_string(),
})
.attach_printable("Failed while updating Gsm rule")
.map(services::ApplicationResponse::Json)
}

#[instrument(skip_all)]
pub async fn delete_gsm_rule(
state: AppState,
gsm_request: gsm_api_types::GsmDeleteRequest,
) -> RouterResponse<gsm_api_types::GsmDeleteResponse> {
let db = state.store.as_ref();
let gsm_api_types::GsmDeleteRequest {
connector,
flow,
sub_flow,
code,
message,
} = gsm_request;
match GsmInterface::delete_gsm_rule(
db,
connector.to_string(),
flow.to_owned(),
sub_flow.to_owned(),
code.to_owned(),
message.to_owned(),
)
.await
.to_not_found_response(errors::ApiErrorResponse::GenericNotFoundError {
message: "GSM with given key does not exist in our records".to_string(),
})
.attach_printable("Failed while Deleting Gsm rule")
{
Ok(is_deleted) => {
if is_deleted {
Ok(services::ApplicationResponse::Json(
gsm_api_types::GsmDeleteResponse {
gsm_rule_delete: true,
connector,
flow,
sub_flow,
code,
},
))
} else {
Err(errors::ApiErrorResponse::InternalServerError)
.into_report()
.attach_printable("Failed while Deleting Gsm rule, got response as false")
}
}
Err(err) => Err(err),
}
}
1 change: 1 addition & 0 deletions crates/router/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ pub fn mk_app(
.service(routes::Files::server(state.clone()))
.service(routes::Disputes::server(state.clone()))
.service(routes::Routing::server(state.clone()))
.service(routes::Gsm::server(state.clone()))
}

#[cfg(all(feature = "olap", feature = "kms"))]
Expand Down
3 changes: 2 additions & 1 deletion crates/router/src/routes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub mod disputes;
pub mod dummy_connector;
pub mod ephemeral_key;
pub mod files;
pub mod gsm;
pub mod health;
pub mod lock_utils;
pub mod mandates;
Expand All @@ -36,7 +37,7 @@ pub use self::app::Routing;
pub use self::app::Verify;
pub use self::app::{
ApiKeys, AppState, BusinessProfile, Cache, Cards, Configs, Customers, Disputes, EphemeralKey,
Files, Health, Mandates, MerchantAccount, MerchantConnectorAccount, PaymentLink,
Files, Gsm, Health, Mandates, MerchantAccount, MerchantConnectorAccount, PaymentLink,
PaymentMethods, Payments, Refunds, Webhooks,
};
#[cfg(feature = "stripe")]
Expand Down
16 changes: 15 additions & 1 deletion crates/router/src/routes/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use super::routing as cloud_routing;
#[cfg(all(feature = "olap", feature = "kms"))]
use super::verification::{apple_pay_merchant_registration, retrieve_apple_pay_verified_domains};
#[cfg(feature = "olap")]
use super::{admin::*, api_keys::*, disputes::*, files::*};
use super::{admin::*, api_keys::*, disputes::*, files::*, gsm::*};
use super::{cache::*, health::*, payment_link::*};
#[cfg(any(feature = "olap", feature = "oltp"))]
use super::{configs::*, customers::*, mandates::*, payments::*, refunds::*};
Expand Down Expand Up @@ -666,6 +666,20 @@ impl BusinessProfile {
}
}

pub struct Gsm;

#[cfg(feature = "olap")]
impl Gsm {
pub fn server(state: AppState) -> Scope {
web::scope("/gsm")
.app_data(web::Data::new(state))
.service(web::resource("").route(web::post().to(create_gsm_rule)))
.service(web::resource("/get").route(web::post().to(get_gsm_rule)))
.service(web::resource("/update").route(web::post().to(update_gsm_rule)))
.service(web::resource("/delete").route(web::post().to(delete_gsm_rule)))
Comment on lines +677 to +679
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the endpoints and http methods do not match, ideally get should go with the GET http method, same for the rest

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For all CRUD APIs we need payload with connector, flow, sub_flow, code and message fields

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The GET endpoint can use query parameters if the values are all single values (and not a list of values).

}
}

#[cfg(all(feature = "olap", feature = "kms"))]
pub struct Verify;

Expand Down
Loading