Skip to content

Commit

Permalink
resolve comments
Browse files Browse the repository at this point in the history
  • Loading branch information
sai-harsha-vardhan committed Nov 4, 2024
1 parent 8727a31 commit 29bea14
Show file tree
Hide file tree
Showing 8 changed files with 110 additions and 18 deletions.
2 changes: 2 additions & 0 deletions crates/api_models/src/payments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4619,6 +4619,8 @@ pub struct PaymentStartRedirectionRequest {
pub struct PaymentStartRedirectionParams {
/// The identifier for the Merchant Account.
pub merchant_id: id_type::MerchantId,
/// The identifier for business profile
pub profile_id: id_type::ProfileId,
}

/// Fee information to be charged on the payment being collected
Expand Down
11 changes: 11 additions & 0 deletions crates/hyperswitch_domain_models/src/payments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,17 @@ impl PaymentIntent {
pub fn get_id(&self) -> &id_type::GlobalPaymentId {
&self.id
}

#[cfg(feature = "v2")]
pub fn create_start_redirection_url(&self, base_url: &str) -> String {
format!(
"{}/v2/payments/{}/start_redirection?merchant_id={}&profile_id={}",
base_url,
self.get_id().get_string_repr(),
self.merchant_id.get_string_repr(),
self.profile_id.get_string_repr()
)
}
}

#[cfg(feature = "v2")]
Expand Down
7 changes: 6 additions & 1 deletion crates/router/src/core/payments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5947,6 +5947,10 @@ pub async fn payment_start_redirection(
.await
.to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;

// validate session expiry
helpers::authenticate_client_secret(Some(&payment_intent.client_secret), &payment_intent)?;

//TODO: send valid html error pages in this case, or atleast redirect to valid html error pages
utils::when(
payment_intent.status != storage_enums::IntentStatus::RequiresCustomerAction,
|| {
Expand All @@ -5972,7 +5976,8 @@ pub async fn payment_start_redirection(
storage_scheme,
)
.await
.to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Error while fetching payment_attempt")?;
let redirection_data = payment_attempt
.authentication_data
.clone()
Expand Down
10 changes: 0 additions & 10 deletions crates/router/src/core/payments/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1152,16 +1152,6 @@ pub fn create_startpay_url(
)
}

#[cfg(feature = "v2")]
pub fn create_start_redirection_url(base_url: &str, payment_intent: &PaymentIntent) -> String {
format!(
"{}/v2/payments/{}/start_redirection?merchant_id={}",
base_url,
payment_intent.get_id().get_string_repr(),
payment_intent.merchant_id.get_string_repr()
)
}

pub fn create_redirect_url(
router_base_url: &String,
payment_attempt: &PaymentAttempt,
Expand Down
3 changes: 2 additions & 1 deletion crates/router/src/core/payments/transformers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -891,9 +891,10 @@ where
.clone()
.map(api_models::payments::ErrorDetails::foreign_from);

// TODO: Add support for other next actions, currently only supporting redirect to url
let next_action = payment_attempt.authentication_data.as_ref().map(|_| {
api_models::payments::NextActionData::RedirectToUrl {
redirect_to_url: helpers::create_start_redirection_url(base_url, payment_intent),
redirect_to_url: payment_intent.create_start_redirection_url(base_url),
}
});

Expand Down
8 changes: 6 additions & 2 deletions crates/router/src/routes/payments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2071,6 +2071,7 @@ pub async fn payments_start_redirection(
tracing::Span::current().record("payment_id", global_payment_id.get_string_repr());

let merchant_id = &payload.merchant_id;
let profile_id = &payload.profile_id;

let payment_start_redirection_request = api_models::payments::PaymentStartRedirectionRequest {
id: global_payment_id.clone(),
Expand All @@ -2088,7 +2089,7 @@ pub async fn payments_start_redirection(
state,
&req,
payment_start_redirection_request.clone(),
|state, auth: auth::AuthenticationData, _req, req_state| async {
|state, auth: auth::AuthenticationDataV2, _req, req_state| async {
payments::payment_start_redirection(
state,
auth.merchant_account,
Expand All @@ -2097,7 +2098,10 @@ pub async fn payments_start_redirection(
)
.await
},
&auth::MerchantIdAuth(merchant_id.clone()),
&auth::MerchantIdAndProfileIdAuth {
merchant_id: merchant_id.clone(),
profile_id: profile_id.clone(),
},
locking_action,
))
.await
Expand Down
83 changes: 83 additions & 0 deletions crates/router/src/services/authentication.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,10 @@ pub enum AuthenticationType {
MerchantId {
merchant_id: id_type::MerchantId,
},
MerchantIdAndProfileId {
merchant_id: id_type::MerchantId,
profile_id: id_type::ProfileId,
},
PublishableKey {
merchant_id: id_type::MerchantId,
},
Expand Down Expand Up @@ -153,6 +157,7 @@ impl AuthenticationType {
}
| Self::AdminApiAuthWithMerchantId { merchant_id }
| Self::MerchantId { merchant_id }
| Self::MerchantIdAndProfileId { merchant_id, .. }
| Self::PublishableKey { merchant_id }
| Self::MerchantJwt {
merchant_id,
Expand Down Expand Up @@ -1142,6 +1147,84 @@ where
}
}

#[derive(Debug)]
#[cfg(feature = "v2")]
pub struct MerchantIdAndProfileIdAuth {
pub merchant_id: id_type::MerchantId,
pub profile_id: id_type::ProfileId,
}

#[async_trait]
#[cfg(feature = "v2")]
impl<A> AuthenticateAndFetch<AuthenticationDataV2, A> for MerchantIdAndProfileIdAuth
where
A: SessionStateInfo + Sync,
{
async fn authenticate_and_fetch(
&self,
_request_headers: &HeaderMap,
state: &A,
) -> RouterResult<(AuthenticationDataV2, AuthenticationType)> {
let key_manager_state = &(&state.session_state()).into();
let key_store = state
.store()
.get_merchant_key_store_by_merchant_id(
key_manager_state,
&self.merchant_id,
&state.store().get_master_key().to_vec().into(),
)
.await
.map_err(|e| {
if e.current_context().is_db_not_found() {
e.change_context(errors::ApiErrorResponse::Unauthorized)
} else {
e.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Failed to fetch merchant key store for the merchant id")
}
})?;

let merchant = state
.store()
.find_merchant_account_by_merchant_id(key_manager_state, &self.merchant_id, &key_store)
.await
.map_err(|e| {
if e.current_context().is_db_not_found() {
e.change_context(errors::ApiErrorResponse::Unauthorized)
} else {
e.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Failed to fetch merchant account for the merchant id")
}
})?;

let profile = state
.store()
.find_business_profile_by_profile_id(key_manager_state, &key_store, &self.profile_id)
.await
.map_err(|e| {
if e.current_context().is_db_not_found() {
e.change_context(errors::ApiErrorResponse::Unauthorized)
} else {
e.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Failed to fetch business profile for the profile id")
}
})?;

let auth = AuthenticationDataV2 {
merchant_account: merchant,
key_store,
profile,
};

Ok((
auth.clone(),
AuthenticationType::MerchantIdAndProfileId {
merchant_id: auth.merchant_account.get_id().clone(),
profile_id: auth.profile.get_id().clone(),
},
))
}
}

#[derive(Debug)]
pub struct PublishableKeyAuth;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,5 @@ ALTER TABLE payment_intent ALTER COLUMN session_expiry SET NOT NULL;
-- This migration is to make fields optional in payment_intent table
ALTER TABLE payment_intent ALTER COLUMN active_attempt_id DROP NOT NULL;

-- This migration is to make fields optional in payment_intent table
ALTER TABLE payment_intent
ALTER COLUMN active_attempt_id DROP NOT NULL;

ALTER TABLE payment_intent
ALTER COLUMN active_attempt_id DROP DEFAULT;

0 comments on commit 29bea14

Please sign in to comment.