mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-11-03 05:17:02 +08:00
refactor(webhook_events): allow listing unique webhook events based on profile ID (#5598)
This commit is contained in:
@ -15,23 +15,23 @@ const INITIAL_DELIVERY_ATTEMPTS_LIST_MAX_LIMIT: i64 = 100;
|
||||
#[derive(Debug)]
|
||||
enum MerchantAccountOrBusinessProfile {
|
||||
MerchantAccount(domain::MerchantAccount),
|
||||
#[allow(dead_code)]
|
||||
BusinessProfile(domain::BusinessProfile),
|
||||
}
|
||||
|
||||
#[instrument(skip(state))]
|
||||
pub async fn list_initial_delivery_attempts(
|
||||
state: SessionState,
|
||||
merchant_id_or_profile_id: String,
|
||||
merchant_id: common_utils::id_type::MerchantId,
|
||||
constraints: api::webhook_events::EventListConstraints,
|
||||
) -> RouterResponse<Vec<api::webhook_events::EventListItemResponse>> {
|
||||
let profile_id = constraints.profile_id.clone();
|
||||
let constraints =
|
||||
api::webhook_events::EventListConstraintsInternal::foreign_try_from(constraints)?;
|
||||
|
||||
let store = state.store.as_ref();
|
||||
let key_manager_state = &(&state).into();
|
||||
let (account, key_store) =
|
||||
determine_identifier_and_get_key_store(state.clone(), merchant_id_or_profile_id).await?;
|
||||
get_account_and_key_store(state.clone(), merchant_id, profile_id).await?;
|
||||
|
||||
let events = match constraints {
|
||||
api_models::webhook_events::EventListConstraintsInternal::ObjectIdFilter { object_id } => {
|
||||
@ -110,38 +110,31 @@ pub async fn list_initial_delivery_attempts(
|
||||
#[instrument(skip(state))]
|
||||
pub async fn list_delivery_attempts(
|
||||
state: SessionState,
|
||||
merchant_id_or_profile_id: String,
|
||||
merchant_id: common_utils::id_type::MerchantId,
|
||||
initial_attempt_id: String,
|
||||
) -> RouterResponse<Vec<api::webhook_events::EventRetrieveResponse>> {
|
||||
let store = state.store.as_ref();
|
||||
|
||||
let (account, key_store) =
|
||||
determine_identifier_and_get_key_store(state.clone(), merchant_id_or_profile_id).await?;
|
||||
let key_manager_state = &(&state).into();
|
||||
let events = match account {
|
||||
MerchantAccountOrBusinessProfile::MerchantAccount(merchant_account) => {
|
||||
store
|
||||
.list_events_by_merchant_id_initial_attempt_id(
|
||||
key_manager_state,
|
||||
merchant_account.get_id(),
|
||||
&initial_attempt_id,
|
||||
&key_store,
|
||||
)
|
||||
.await
|
||||
}
|
||||
MerchantAccountOrBusinessProfile::BusinessProfile(business_profile) => {
|
||||
store
|
||||
.list_events_by_profile_id_initial_attempt_id(
|
||||
key_manager_state,
|
||||
&business_profile.profile_id,
|
||||
&initial_attempt_id,
|
||||
&key_store,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
.attach_printable("Failed to list delivery attempts for initial event")?;
|
||||
|
||||
let key_store = store
|
||||
.get_merchant_key_store_by_merchant_id(
|
||||
key_manager_state,
|
||||
&merchant_id,
|
||||
&store.get_master_key().to_vec().into(),
|
||||
)
|
||||
.await
|
||||
.to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;
|
||||
|
||||
let events = store
|
||||
.list_events_by_merchant_id_initial_attempt_id(
|
||||
key_manager_state,
|
||||
&merchant_id,
|
||||
&initial_attempt_id,
|
||||
&key_store,
|
||||
)
|
||||
.await
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
.attach_printable("Failed to list delivery attempts for initial event")?;
|
||||
|
||||
if events.is_empty() {
|
||||
Err(error_stack::report!(
|
||||
@ -161,13 +154,20 @@ pub async fn list_delivery_attempts(
|
||||
#[instrument(skip(state))]
|
||||
pub async fn retry_delivery_attempt(
|
||||
state: SessionState,
|
||||
merchant_id_or_profile_id: String,
|
||||
merchant_id: common_utils::id_type::MerchantId,
|
||||
event_id: String,
|
||||
) -> RouterResponse<api::webhook_events::EventRetrieveResponse> {
|
||||
let store = state.store.as_ref();
|
||||
let key_manager_state = &(&state).into();
|
||||
let (account, key_store) =
|
||||
determine_identifier_and_get_key_store(state.clone(), merchant_id_or_profile_id).await?;
|
||||
|
||||
let key_store = store
|
||||
.get_merchant_key_store_by_merchant_id(
|
||||
key_manager_state,
|
||||
&merchant_id,
|
||||
&store.get_master_key().to_vec().into(),
|
||||
)
|
||||
.await
|
||||
.to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;
|
||||
|
||||
let event_to_retry = store
|
||||
.find_event_by_merchant_id_event_id(
|
||||
@ -179,25 +179,16 @@ pub async fn retry_delivery_attempt(
|
||||
.await
|
||||
.to_not_found_response(errors::ApiErrorResponse::EventNotFound)?;
|
||||
|
||||
let business_profile = match account {
|
||||
MerchantAccountOrBusinessProfile::MerchantAccount(_) => {
|
||||
let business_profile_id = event_to_retry
|
||||
.business_profile_id
|
||||
.get_required_value("business_profile_id")
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
.attach_printable("Failed to read business profile ID from event to retry")?;
|
||||
store
|
||||
.find_business_profile_by_profile_id(
|
||||
key_manager_state,
|
||||
&key_store,
|
||||
&business_profile_id,
|
||||
)
|
||||
.await
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
.attach_printable("Failed to find business profile")
|
||||
}
|
||||
MerchantAccountOrBusinessProfile::BusinessProfile(business_profile) => Ok(business_profile),
|
||||
}?;
|
||||
let business_profile_id = event_to_retry
|
||||
.business_profile_id
|
||||
.get_required_value("business_profile_id")
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
.attach_printable("Failed to read business profile ID from event to retry")?;
|
||||
let business_profile = store
|
||||
.find_business_profile_by_profile_id(key_manager_state, &key_store, &business_profile_id)
|
||||
.await
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
.attach_printable("Failed to find business profile")?;
|
||||
|
||||
let delivery_attempt = storage::enums::WebhookDeliveryAttempt::ManualRetry;
|
||||
let new_event_id = super::utils::generate_event_id();
|
||||
@ -271,77 +262,65 @@ pub async fn retry_delivery_attempt(
|
||||
))
|
||||
}
|
||||
|
||||
async fn determine_identifier_and_get_key_store(
|
||||
async fn get_account_and_key_store(
|
||||
state: SessionState,
|
||||
merchant_id_or_profile_id: String,
|
||||
merchant_id: common_utils::id_type::MerchantId,
|
||||
profile_id: Option<String>,
|
||||
) -> errors::RouterResult<(MerchantAccountOrBusinessProfile, domain::MerchantKeyStore)> {
|
||||
let store = state.store.as_ref();
|
||||
let key_manager_state = &(&state).into();
|
||||
let merchant_id = common_utils::id_type::MerchantId::try_from(std::borrow::Cow::from(
|
||||
merchant_id_or_profile_id.clone(),
|
||||
))
|
||||
.change_context(errors::ApiErrorResponse::InvalidDataValue {
|
||||
field_name: "merchant_id",
|
||||
})?;
|
||||
match store
|
||||
let merchant_key_store = store
|
||||
.get_merchant_key_store_by_merchant_id(
|
||||
key_manager_state,
|
||||
&merchant_id,
|
||||
&store.get_master_key().to_vec().into(),
|
||||
)
|
||||
.await
|
||||
{
|
||||
// Since a merchant key store was found with `merchant_id` = `merchant_id_or_profile_id`,
|
||||
// `merchant_id_or_profile_id` is a valid merchant ID.
|
||||
// Find a merchant account having `merchant_id` = `merchant_id_or_profile_id`.
|
||||
Ok(key_store) => {
|
||||
let merchant_account = store
|
||||
.find_merchant_account_by_merchant_id(key_manager_state, &merchant_id, &key_store)
|
||||
.to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;
|
||||
|
||||
match profile_id {
|
||||
// If profile ID is specified, return business profile, since a business profile is more
|
||||
// specific than a merchant account.
|
||||
Some(profile_id) => {
|
||||
let business_profile = store
|
||||
.find_business_profile_by_merchant_id_profile_id(
|
||||
key_manager_state,
|
||||
&merchant_key_store,
|
||||
&merchant_id,
|
||||
&profile_id,
|
||||
)
|
||||
.await
|
||||
.to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;
|
||||
.attach_printable_lazy(|| {
|
||||
format!(
|
||||
"Failed to find business profile by merchant_id `{merchant_id:?}` and profile_id `{profile_id}`. \
|
||||
The merchant_id associated with the business profile `{profile_id}` may be \
|
||||
different than the merchant_id specified (`{merchant_id:?}`)."
|
||||
)
|
||||
})
|
||||
.to_not_found_response(errors::ApiErrorResponse::BusinessProfileNotFound {
|
||||
id: profile_id,
|
||||
})?;
|
||||
|
||||
Ok((
|
||||
MerchantAccountOrBusinessProfile::MerchantAccount(merchant_account),
|
||||
key_store,
|
||||
MerchantAccountOrBusinessProfile::BusinessProfile(business_profile),
|
||||
merchant_key_store,
|
||||
))
|
||||
}
|
||||
|
||||
/*
|
||||
// Since no merchant key store was found with `merchant_id` = `merchant_id_or_profile_id`,
|
||||
// `merchant_id_or_profile_id` is not a valid merchant ID.
|
||||
// Assuming that `merchant_id_or_profile_id` is a business profile ID, try to find a
|
||||
// business profile having `profile_id` = `merchant_id_or_profile_id`.
|
||||
Err(error) if error.current_context().is_db_not_found() => {
|
||||
router_env::logger::debug!(
|
||||
?error,
|
||||
%merchant_id_or_profile_id,
|
||||
"Failed to find merchant key store for the specified merchant ID or business profile ID"
|
||||
);
|
||||
|
||||
let business_profile = store
|
||||
.find_business_profile_by_profile_id(&merchant_id_or_profile_id)
|
||||
.await
|
||||
.to_not_found_response(errors::ApiErrorResponse::BusinessProfileNotFound {
|
||||
id: merchant_id_or_profile_id,
|
||||
})?;
|
||||
|
||||
let key_store = store
|
||||
.get_merchant_key_store_by_merchant_id(
|
||||
None => {
|
||||
let merchant_account = store
|
||||
.find_merchant_account_by_merchant_id(
|
||||
key_manager_state,
|
||||
&business_profile.merchant_id,
|
||||
&store.get_master_key().to_vec().into(),
|
||||
&merchant_id,
|
||||
&merchant_key_store,
|
||||
)
|
||||
.await
|
||||
.to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;
|
||||
|
||||
Ok((
|
||||
MerchantAccountOrBusinessProfile::BusinessProfile(business_profile),
|
||||
key_store,
|
||||
MerchantAccountOrBusinessProfile::MerchantAccount(merchant_account),
|
||||
merchant_key_store,
|
||||
))
|
||||
}
|
||||
*/
|
||||
Err(error) => Err(error)
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
.attach_printable("Failed to find merchant key store by merchant ID"),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user