feat(events): add extracted fields based on req/res types (#2795)

This commit is contained in:
Sampras Lopes
2023-11-08 21:31:53 +05:30
committed by GitHub
parent 25a73c29a4
commit 89857941b0
40 changed files with 664 additions and 69 deletions

2
Cargo.lock generated
View File

@ -1503,7 +1503,6 @@ checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
name = "common_enums"
version = "0.1.0"
dependencies = [
"common_utils",
"diesel",
"router_derive",
"serde",
@ -1519,6 +1518,7 @@ version = "0.1.0"
dependencies = [
"async-trait",
"bytes",
"common_enums",
"diesel",
"error-stack",
"fake",

View File

@ -893,6 +893,8 @@ pub struct ToggleKVResponse {
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct ToggleKVRequest {
#[serde(skip_deserializing)]
pub merchant_id: String,
/// Status of KV for the specific merchant
#[schema(example = true)]
pub kv_enabled: bool,

View File

@ -129,6 +129,12 @@ pub struct UpdateApiKeyRequest {
/// rotating your keys once every 6 months.
#[schema(example = "2022-09-10T10:11:12Z")]
pub expiration: Option<ApiKeyExpiration>,
#[serde(skip_deserializing)]
pub key_id: String,
#[serde(skip_deserializing)]
pub merchant_id: String,
}
/// The response body for revoking an API Key.

View File

@ -0,0 +1,74 @@
pub mod customer;
pub mod payment;
#[cfg(feature = "payouts")]
pub mod payouts;
pub mod refund;
pub mod routing;
use common_utils::{
events::{ApiEventMetric, ApiEventsType},
impl_misc_api_event_type,
};
use crate::{
admin::*, api_keys::*, cards_info::*, disputes::*, files::*, mandates::*, payment_methods::*,
payments::*, verifications::*,
};
impl ApiEventMetric for TimeRange {}
impl_misc_api_event_type!(
PaymentMethodId,
PaymentsSessionResponse,
PaymentMethodListResponse,
PaymentMethodCreate,
PaymentLinkInitiateRequest,
RetrievePaymentLinkResponse,
MandateListConstraints,
CreateFileResponse,
DisputeResponse,
SubmitEvidenceRequest,
MerchantConnectorResponse,
MerchantConnectorId,
MandateResponse,
MandateRevokedResponse,
RetrievePaymentLinkRequest,
MandateId,
DisputeListConstraints,
RetrieveApiKeyResponse,
BusinessProfileResponse,
BusinessProfileUpdate,
BusinessProfileCreate,
RevokeApiKeyResponse,
ToggleKVResponse,
ToggleKVRequest,
MerchantAccountDeleteResponse,
MerchantAccountUpdate,
CardInfoResponse,
CreateApiKeyResponse,
CreateApiKeyRequest,
MerchantConnectorDeleteResponse,
MerchantConnectorUpdate,
MerchantConnectorCreate,
MerchantId,
CardsInfoRequest,
MerchantAccountResponse,
MerchantAccountListRequest,
MerchantAccountCreate,
PaymentsSessionRequest,
ApplepayMerchantVerificationRequest,
ApplepayMerchantResponse,
ApplepayVerifiedDomainsResponse,
UpdateApiKeyRequest
);
#[cfg(feature = "stripe")]
impl_misc_api_event_type!(
StripeSetupIntentResponse,
StripeRefundResponse,
StripePaymentIntentListResponse,
StripePaymentIntentResponse,
CustomerDeleteResponse,
CustomerPaymentMethodListResponse,
CreateCustomerResponse
);

View File

@ -0,0 +1,35 @@
use common_utils::events::{ApiEventMetric, ApiEventsType};
use crate::customers::{CustomerDeleteResponse, CustomerId, CustomerRequest, CustomerResponse};
impl ApiEventMetric for CustomerDeleteResponse {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::Customer {
customer_id: self.customer_id.clone(),
})
}
}
impl ApiEventMetric for CustomerRequest {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::Customer {
customer_id: self.customer_id.clone(),
})
}
}
impl ApiEventMetric for CustomerResponse {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::Customer {
customer_id: self.customer_id.clone(),
})
}
}
impl ApiEventMetric for CustomerId {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::Customer {
customer_id: self.customer_id.clone(),
})
}
}

View File

@ -0,0 +1,151 @@
use common_utils::events::{ApiEventMetric, ApiEventsType};
use crate::{
payment_methods::{
CustomerPaymentMethodsListResponse, PaymentMethodDeleteResponse, PaymentMethodListRequest,
PaymentMethodResponse, PaymentMethodUpdate,
},
payments::{
PaymentIdType, PaymentListConstraints, PaymentListFilterConstraints, PaymentListFilters,
PaymentListResponse, PaymentListResponseV2, PaymentsApproveRequest, PaymentsCancelRequest,
PaymentsCaptureRequest, PaymentsRejectRequest, PaymentsRequest, PaymentsResponse,
PaymentsRetrieveRequest, PaymentsStartRequest, RedirectionResponse,
},
};
impl ApiEventMetric for PaymentsRetrieveRequest {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
match self.resource_id {
PaymentIdType::PaymentIntentId(ref id) => Some(ApiEventsType::Payment {
payment_id: id.clone(),
}),
_ => None,
}
}
}
impl ApiEventMetric for PaymentsStartRequest {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::Payment {
payment_id: self.payment_id.clone(),
})
}
}
impl ApiEventMetric for PaymentsCaptureRequest {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::Payment {
payment_id: self.payment_id.to_owned(),
})
}
}
impl ApiEventMetric for PaymentsCancelRequest {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::Payment {
payment_id: self.payment_id.clone(),
})
}
}
impl ApiEventMetric for PaymentsApproveRequest {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::Payment {
payment_id: self.payment_id.clone(),
})
}
}
impl ApiEventMetric for PaymentsRejectRequest {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::Payment {
payment_id: self.payment_id.clone(),
})
}
}
impl ApiEventMetric for PaymentsRequest {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
match self.payment_id {
Some(PaymentIdType::PaymentIntentId(ref id)) => Some(ApiEventsType::Payment {
payment_id: id.clone(),
}),
_ => None,
}
}
}
impl ApiEventMetric for PaymentsResponse {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
self.payment_id
.clone()
.map(|payment_id| ApiEventsType::Payment { payment_id })
}
}
impl ApiEventMetric for PaymentMethodResponse {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::PaymentMethod {
payment_method_id: self.payment_method_id.clone(),
payment_method: Some(self.payment_method),
payment_method_type: self.payment_method_type,
})
}
}
impl ApiEventMetric for PaymentMethodUpdate {}
impl ApiEventMetric for PaymentMethodDeleteResponse {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::PaymentMethod {
payment_method_id: self.payment_method_id.clone(),
payment_method: None,
payment_method_type: None,
})
}
}
impl ApiEventMetric for CustomerPaymentMethodsListResponse {}
impl ApiEventMetric for PaymentMethodListRequest {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::PaymentMethodList {
payment_id: self
.client_secret
.as_ref()
.and_then(|cs| cs.rsplit_once("_secret_"))
.map(|(pid, _)| pid.to_string()),
})
}
}
impl ApiEventMetric for PaymentListFilterConstraints {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::ResourceListAPI)
}
}
impl ApiEventMetric for PaymentListFilters {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::ResourceListAPI)
}
}
impl ApiEventMetric for PaymentListConstraints {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::ResourceListAPI)
}
}
impl ApiEventMetric for PaymentListResponse {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::ResourceListAPI)
}
}
impl ApiEventMetric for PaymentListResponseV2 {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::ResourceListAPI)
}
}
impl ApiEventMetric for RedirectionResponse {}

View File

@ -0,0 +1,29 @@
use common_utils::events::{ApiEventMetric, ApiEventsType};
use crate::payouts::{
PayoutActionRequest, PayoutCreateRequest, PayoutCreateResponse, PayoutRetrieveRequest,
};
impl ApiEventMetric for PayoutRetrieveRequest {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::Payout)
}
}
impl ApiEventMetric for PayoutCreateRequest {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::Payout)
}
}
impl ApiEventMetric for PayoutCreateResponse {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::Payout)
}
}
impl ApiEventMetric for PayoutActionRequest {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::Payout)
}
}

View File

@ -0,0 +1,63 @@
use common_utils::events::{ApiEventMetric, ApiEventsType};
use crate::refunds::{
RefundListMetaData, RefundListRequest, RefundListResponse, RefundRequest, RefundResponse,
RefundUpdateRequest, RefundsRetrieveRequest,
};
impl ApiEventMetric for RefundRequest {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
let payment_id = self.payment_id.clone();
self.refund_id
.clone()
.map(|refund_id| ApiEventsType::Refund {
payment_id: Some(payment_id),
refund_id,
})
}
}
impl ApiEventMetric for RefundResponse {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::Refund {
payment_id: Some(self.payment_id.clone()),
refund_id: self.refund_id.clone(),
})
}
}
impl ApiEventMetric for RefundsRetrieveRequest {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::Refund {
payment_id: None,
refund_id: self.refund_id.clone(),
})
}
}
impl ApiEventMetric for RefundUpdateRequest {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::Refund {
payment_id: None,
refund_id: self.refund_id.clone(),
})
}
}
impl ApiEventMetric for RefundListRequest {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::ResourceListAPI)
}
}
impl ApiEventMetric for RefundListResponse {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::ResourceListAPI)
}
}
impl ApiEventMetric for RefundListMetaData {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::ResourceListAPI)
}
}

View File

@ -0,0 +1,58 @@
use common_utils::events::{ApiEventMetric, ApiEventsType};
use crate::routing::{
LinkedRoutingConfigRetrieveResponse, MerchantRoutingAlgorithm, RoutingAlgorithmId,
RoutingConfigRequest, RoutingDictionaryRecord, RoutingKind,
};
#[cfg(feature = "business_profile_routing")]
use crate::routing::{RoutingRetrieveLinkQuery, RoutingRetrieveQuery};
impl ApiEventMetric for RoutingKind {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::Routing)
}
}
impl ApiEventMetric for MerchantRoutingAlgorithm {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::Routing)
}
}
impl ApiEventMetric for RoutingAlgorithmId {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::Routing)
}
}
impl ApiEventMetric for RoutingDictionaryRecord {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::Routing)
}
}
impl ApiEventMetric for LinkedRoutingConfigRetrieveResponse {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::Routing)
}
}
#[cfg(feature = "business_profile_routing")]
impl ApiEventMetric for RoutingRetrieveQuery {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::Routing)
}
}
impl ApiEventMetric for RoutingConfigRequest {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::Routing)
}
}
#[cfg(feature = "business_profile_routing")]
impl ApiEventMetric for RoutingRetrieveLinkQuery {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::Routing)
}
}

View File

@ -9,6 +9,7 @@ pub mod enums;
pub mod ephemeral_key;
#[cfg(feature = "errors")]
pub mod errors;
pub mod events;
pub mod files;
pub mod mandates;
pub mod organization;

View File

@ -12,7 +12,9 @@ use utoipa::ToSchema;
#[cfg(feature = "payouts")]
use crate::payouts;
use crate::{
admin, enums as api_enums,
admin,
customers::CustomerId,
enums as api_enums,
payments::{self, BankCodeResponse},
};
@ -476,6 +478,8 @@ pub struct RequestPaymentMethodTypes {
#[derive(Debug, Clone, serde::Serialize, Default, ToSchema)]
#[serde(deny_unknown_fields)]
pub struct PaymentMethodListRequest {
#[serde(skip_deserializing)]
pub customer_id: Option<CustomerId>,
/// This is a 15 minute expiry token which shall be used from the client to authenticate and perform sessions from the SDK
#[schema(max_length = 30, min_length = 30, example = "secret_k2uj3he2893ein2d")]
pub client_secret: Option<String>,

View File

@ -2232,7 +2232,9 @@ pub struct PaymentListFilters {
pub authentication_type: Vec<enums::AuthenticationType>,
}
#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize, PartialEq, Eq, Hash)]
#[derive(
Debug, Clone, Copy, serde::Serialize, serde::Deserialize, PartialEq, Eq, Hash, ToSchema,
)]
pub struct TimeRange {
/// The start time to filter payments list or to get list of filters. To get list of filters start time is needed to be passed
#[serde(with = "common_utils::custom_serde::iso8601")]

View File

@ -3,6 +3,7 @@ use serde::{Deserialize, Serialize};
use time::PrimitiveDateTime;
use utoipa::ToSchema;
use super::payments::TimeRange;
use crate::{admin, enums};
#[derive(Default, Debug, ToSchema, Clone, Deserialize, Serialize)]
@ -75,6 +76,8 @@ pub struct RefundsRetrieveRequest {
#[derive(Default, Debug, ToSchema, Clone, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct RefundUpdateRequest {
#[serde(skip)]
pub refund_id: String,
/// An arbitrary string attached to the object. Often useful for displaying to users and your customer support executive
#[schema(max_length = 255, example = "Customer returned the product")]
pub reason: Option<String>,
@ -152,16 +155,6 @@ pub struct RefundListRequest {
pub refund_status: Option<Vec<enums::RefundStatus>>,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash, ToSchema)]
pub struct TimeRange {
/// The start time to filter refunds list or to get list of filters. To get list of filters start time is needed to be passed
#[serde(with = "common_utils::custom_serde::iso8601")]
pub start_time: PrimitiveDateTime,
/// The end time to filter refunds list or to get list of filters. If not passed the default time is now
#[serde(default, with = "common_utils::custom_serde::iso8601::option")]
pub end_time: Option<PrimitiveDateTime>,
}
#[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize, ToSchema)]
pub struct RefundListResponse {
/// The number of refunds included in the list

View File

@ -592,3 +592,8 @@ pub enum RoutingKind {
Config(RoutingDictionary),
RoutingAlgorithm(Vec<RoutingDictionaryRecord>),
}
#[repr(transparent)]
#[derive(serde::Serialize, serde::Deserialize, Debug)]
#[serde(transparent)]
pub struct RoutingAlgorithmId(pub String);

View File

@ -19,7 +19,6 @@ time = { version = "0.3.21", features = ["serde", "serde-well-known", "std"] }
utoipa = { version = "3.3.0", features = ["preserve_order"] }
# First party crates
common_utils = { version = "0.1.0", path = "../common_utils" }
router_derive = { version = "0.1.0", path = "../router_derive" }
[dev-dependencies]

View File

@ -42,6 +42,7 @@ phonenumber = "0.3.3"
# First party crates
masking = { version = "0.1.0", path = "../masking" }
router_env = { version = "0.1.0", path = "../router_env", features = ["log_extra_implicit_fields", "log_custom_entries_to_extra"], optional = true }
common_enums = { version = "0.1.0", path = "../common_enums" }
[target.'cfg(not(target_os = "windows"))'.dependencies]
signal-hook-tokio = { version = "0.3.1", features = ["futures-v0_3"], optional = true }

View File

@ -0,0 +1,91 @@
use common_enums::{PaymentMethod, PaymentMethodType};
use serde::Serialize;
pub trait ApiEventMetric {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
None
}
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
#[serde(tag = "flow_type")]
pub enum ApiEventsType {
Payout,
Payment {
payment_id: String,
},
Refund {
payment_id: Option<String>,
refund_id: String,
},
PaymentMethod {
payment_method_id: String,
payment_method: Option<PaymentMethod>,
payment_method_type: Option<PaymentMethodType>,
},
Customer {
customer_id: String,
},
User {
//specified merchant_id will overridden on global defined
merchant_id: String,
user_id: String,
},
PaymentMethodList {
payment_id: Option<String>,
},
Webhooks {
connector: String,
payment_id: Option<String>,
},
Routing,
ResourceListAPI,
PaymentRedirectionResponse,
// TODO: This has to be removed once the corresponding apiEventTypes are created
Miscellaneous,
}
impl ApiEventMetric for serde_json::Value {}
impl ApiEventMetric for () {}
impl<Q: ApiEventMetric, E> ApiEventMetric for Result<Q, E> {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
match self {
Ok(q) => q.get_api_event_type(),
Err(_) => None,
}
}
}
// TODO: Ideally all these types should be replaced by newtype responses
impl<T> ApiEventMetric for Vec<T> {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::Miscellaneous)
}
}
#[macro_export]
macro_rules! impl_misc_api_event_type {
($($type:ty),+) => {
$(
impl ApiEventMetric for $type {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::Miscellaneous)
}
}
)+
};
}
impl_misc_api_event_type!(
String,
(&String, &String),
(Option<i64>, Option<i64>, String),
bool
);
impl<T: ApiEventMetric> ApiEventMetric for &T {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
T::get_api_event_type(self)
}
}

View File

@ -6,6 +6,8 @@ pub mod consts;
pub mod crypto;
pub mod custom_serde;
pub mod errors;
#[allow(missing_docs)] // Todo: add docs
pub mod events;
pub mod ext_traits;
pub mod fp_utils;
pub mod pii;

View File

@ -14,3 +14,9 @@ pub struct EphemeralKey {
pub expires: i64,
pub secret: String,
}
impl common_utils::events::ApiEventMetric for EphemeralKey {
fn get_api_event_type(&self) -> Option<common_utils::events::ApiEventsType> {
Some(common_utils::events::ApiEventsType::Miscellaneous)
}
}

View File

@ -227,3 +227,12 @@ pub struct RefundCoreWorkflow {
pub merchant_id: String,
pub payment_id: String,
}
impl common_utils::events::ApiEventMetric for Refund {
fn get_api_event_type(&self) -> Option<common_utils::events::ApiEventsType> {
Some(common_utils::events::ApiEventsType::Refund {
payment_id: Some(self.payment_id.clone()),
refund_id: self.refund_id.clone(),
})
}
}

View File

@ -149,8 +149,8 @@ pub async fn refund_update(
path: web::Path<String>,
form_payload: web::Form<types::StripeUpdateRefundRequest>,
) -> HttpResponse {
let refund_id = path.into_inner();
let payload = form_payload.into_inner();
let mut payload = form_payload.into_inner();
payload.refund_id = path.into_inner();
let create_refund_update_req: refund_types::RefundUpdateRequest = payload.into();
let flow = Flow::RefundsUpdate;
@ -169,9 +169,7 @@ pub async fn refund_update(
state.into_inner(),
&req,
create_refund_update_req,
|state, auth, req| {
refunds::refund_update_core(state, auth.merchant_account, &refund_id, req)
},
|state, auth, req| refunds::refund_update_core(state, auth.merchant_account, req),
&auth::ApiKeyAuth,
api_locking::LockAction::NotApplicable,
))

View File

@ -17,6 +17,8 @@ pub struct StripeCreateRefundRequest {
#[derive(Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
pub struct StripeUpdateRefundRequest {
#[serde(skip)]
pub refund_id: String,
pub metadata: Option<pii::SecretSerdeValue>,
}
@ -58,6 +60,7 @@ impl From<StripeCreateRefundRequest> for refunds::RefundRequest {
impl From<StripeUpdateRefundRequest> for refunds::RefundUpdateRequest {
fn from(req: StripeUpdateRefundRequest) -> Self {
Self {
refund_id: req.refund_id,
metadata: req.metadata,
reason: None,
}

View File

@ -7,6 +7,7 @@ use serde::Serialize;
use crate::{
core::{api_locking, errors},
events::api_logs::ApiEventMetric,
routes::{app::AppStateInfo, metrics},
services::{self, api, authentication as auth, logger},
};
@ -25,12 +26,12 @@ where
F: Fn(A, U, T) -> Fut,
Fut: Future<Output = CustomResult<api::ApplicationResponse<Q>, E2>>,
E2: ErrorSwitch<E> + std::error::Error + Send + Sync + 'static,
Q: Serialize + std::fmt::Debug + 'a,
Q: Serialize + std::fmt::Debug + 'a + ApiEventMetric,
S: TryFrom<Q> + Serialize,
E: Serialize + error_stack::Context + actix_web::ResponseError + Clone,
error_stack::Report<E>: services::EmbedError,
errors::ApiErrorResponse: ErrorSwitch<E>,
T: std::fmt::Debug + Serialize,
T: std::fmt::Debug + Serialize + ApiEventMetric,
A: AppStateInfo + Clone,
{
let request_method = request.method().as_str();

View File

@ -294,10 +294,10 @@ pub async fn retrieve_api_key(
#[instrument(skip_all)]
pub async fn update_api_key(
state: AppState,
merchant_id: &str,
key_id: &str,
api_key: api::UpdateApiKeyRequest,
) -> RouterResponse<api::RetrieveApiKeyResponse> {
let merchant_id = api_key.merchant_id.clone();
let key_id = api_key.key_id.clone();
let store = state.store.as_ref();
let api_key = store
@ -313,7 +313,7 @@ pub async fn update_api_key(
{
let expiry_reminder_days = state.conf.api_keys.expiry_reminder_days.clone();
let task_id = generate_task_id_for_api_key_expiry_workflow(key_id);
let task_id = generate_task_id_for_api_key_expiry_workflow(&key_id);
// In order to determine how to update the existing process in the process_tracker table,
// we need access to the current entry in the table.
let existing_process_tracker_task = store
@ -339,7 +339,7 @@ pub async fn update_api_key(
// If an expiry is set to 'never'
else {
// Process exist in process, revoke it
revoke_api_key_expiry_task(store, key_id)
revoke_api_key_expiry_task(store, &key_id)
.await
.into_report()
.change_context(errors::ApiErrorResponse::InternalServerError)

View File

@ -476,14 +476,13 @@ pub async fn sync_refund_with_gateway(
pub async fn refund_update_core(
state: AppState,
merchant_account: domain::MerchantAccount,
refund_id: &str,
req: refunds::RefundUpdateRequest,
) -> RouterResponse<refunds::RefundResponse> {
let db = state.store.as_ref();
let refund = db
.find_refund_by_merchant_id_refund_id(
&merchant_account.merchant_id,
refund_id,
&req.refund_id,
merchant_account.storage_scheme,
)
.await
@ -501,7 +500,9 @@ pub async fn refund_update_core(
)
.await
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable_lazy(|| format!("Unable to update refund with refund_id: {refund_id}"))?;
.attach_printable_lazy(|| {
format!("Unable to update refund with refund_id: {}", req.refund_id)
})?;
Ok(services::ApplicationResponse::Json(response.foreign_into()))
}
@ -698,7 +699,7 @@ pub async fn refund_list(
pub async fn refund_filter_list(
state: AppState,
merchant_account: domain::MerchantAccount,
req: api_models::refunds::TimeRange,
req: api_models::payments::TimeRange,
) -> RouterResponse<api_models::refunds::RefundListMetaData> {
let db = state.store;
let filter_list = db

View File

@ -1,7 +1,7 @@
pub mod helpers;
pub mod transformers;
use api_models::routing as routing_types;
use api_models::routing::{self as routing_types, RoutingAlgorithmId};
#[cfg(feature = "business_profile_routing")]
use api_models::routing::{RoutingRetrieveLinkQuery, RoutingRetrieveQuery};
#[cfg(not(feature = "business_profile_routing"))]
@ -319,14 +319,14 @@ pub async fn link_routing_config(
pub async fn retrieve_routing_config(
state: AppState,
merchant_account: domain::MerchantAccount,
algorithm_id: String,
algorithm_id: RoutingAlgorithmId,
) -> RouterResponse<routing_types::MerchantRoutingAlgorithm> {
let db = state.store.as_ref();
#[cfg(feature = "business_profile_routing")]
{
let routing_algorithm = db
.find_routing_algorithm_by_algorithm_id_merchant_id(
&algorithm_id,
&algorithm_id.0,
&merchant_account.merchant_id,
)
.await
@ -356,13 +356,13 @@ pub async fn retrieve_routing_config(
let record = merchant_dictionary
.records
.into_iter()
.find(|rec| rec.id == algorithm_id)
.find(|rec| rec.id == algorithm_id.0)
.ok_or(errors::ApiErrorResponse::ResourceIdNotFound)
.into_report()
.attach_printable("Algorithm with the given ID not found in the merchant dictionary")?;
let algorithm_config = db
.find_config_by_key(&algorithm_id)
.find_config_by_key(&algorithm_id.0)
.await
.change_context(errors::ApiErrorResponse::ResourceIdNotFound)
.attach_printable("Routing config not found in DB")?;

View File

@ -1,5 +1,4 @@
pub mod utils;
use actix_web::web;
use api_models::verifications::{self, ApplepayMerchantResponse};
use common_utils::{errors::CustomResult, ext_traits::Encode};
use error_stack::ResultExt;
@ -18,7 +17,7 @@ const APPLEPAY_INTERNAL_MERCHANT_NAME: &str = "Applepay_merchant";
pub async fn verify_merchant_creds_for_applepay(
state: AppState,
_req: &actix_web::HttpRequest,
body: web::Json<verifications::ApplepayMerchantVerificationRequest>,
body: verifications::ApplepayMerchantVerificationRequest,
kms_config: &kms::KmsConfig,
merchant_id: String,
) -> CustomResult<

View File

@ -78,7 +78,7 @@ pub trait RefundInterface {
async fn filter_refund_by_meta_constraints(
&self,
merchant_id: &str,
refund_details: &api_models::refunds::TimeRange,
refund_details: &api_models::payments::TimeRange,
storage_scheme: enums::MerchantStorageScheme,
) -> CustomResult<api_models::refunds::RefundListMetaData, errors::StorageError>;
@ -232,7 +232,7 @@ mod storage {
async fn filter_refund_by_meta_constraints(
&self,
merchant_id: &str,
refund_details: &api_models::refunds::TimeRange,
refund_details: &api_models::payments::TimeRange,
_storage_scheme: enums::MerchantStorageScheme,
) -> CustomResult<api_models::refunds::RefundListMetaData, errors::StorageError> {
let conn = connection::pg_connection_read(self).await?;
@ -707,7 +707,7 @@ mod storage {
async fn filter_refund_by_meta_constraints(
&self,
merchant_id: &str,
refund_details: &api_models::refunds::TimeRange,
refund_details: &api_models::payments::TimeRange,
_storage_scheme: enums::MerchantStorageScheme,
) -> CustomResult<api_models::refunds::RefundListMetaData, errors::StorageError> {
let conn = connection::pg_connection_read(self).await?;
@ -979,7 +979,7 @@ impl RefundInterface for MockDb {
async fn filter_refund_by_meta_constraints(
&self,
_merchant_id: &str,
refund_details: &api_models::refunds::TimeRange,
refund_details: &api_models::payments::TimeRange,
_storage_scheme: enums::MerchantStorageScheme,
) -> CustomResult<api_models::refunds::RefundListMetaData, errors::StorageError> {
let refunds = self.refunds.lock().await;

View File

@ -1,10 +1,25 @@
use actix_web::HttpRequest;
pub use common_utils::events::{ApiEventMetric, ApiEventsType};
use common_utils::impl_misc_api_event_type;
use router_env::{tracing_actix_web::RequestId, types::FlowMetric};
use serde::Serialize;
use time::OffsetDateTime;
use super::{EventType, RawEvent};
use crate::services::authentication::AuthenticationType;
#[cfg(feature = "dummy_connector")]
use crate::routes::dummy_connector::types::{
DummyConnectorPaymentCompleteRequest, DummyConnectorPaymentConfirmRequest,
DummyConnectorPaymentRequest, DummyConnectorPaymentResponse,
DummyConnectorPaymentRetrieveRequest, DummyConnectorRefundRequest,
DummyConnectorRefundResponse, DummyConnectorRefundRetrieveRequest,
};
use crate::{
core::payments::PaymentsRedirectResponseData,
services::{authentication::AuthenticationType, ApplicationResponse, PaymentLinkFormData},
types::api::{
AttachEvidenceRequest, Config, ConfigUpdate, CreateFileRequest, DisputeId, FileId,
},
};
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct ApiEvent {
@ -20,6 +35,8 @@ pub struct ApiEvent {
ip_addr: Option<String>,
url_path: String,
response: Option<serde_json::Value>,
#[serde(flatten)]
event_type: ApiEventsType,
}
impl ApiEvent {
@ -32,6 +49,7 @@ impl ApiEvent {
request: serde_json::Value,
response: Option<serde_json::Value>,
auth_type: AuthenticationType,
event_type: ApiEventsType,
http_req: &HttpRequest,
) -> Self {
Self {
@ -52,6 +70,7 @@ impl ApiEvent {
.get("user-agent")
.and_then(|user_agent_value| user_agent_value.to_str().ok().map(ToOwned::to_owned)),
url_path: http_req.path().to_string(),
event_type,
}
}
}
@ -67,3 +86,35 @@ impl TryFrom<ApiEvent> for RawEvent {
})
}
}
impl<T: ApiEventMetric> ApiEventMetric for ApplicationResponse<T> {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
match self {
Self::Json(r) => r.get_api_event_type(),
Self::JsonWithHeaders((r, _)) => r.get_api_event_type(),
_ => None,
}
}
}
impl_misc_api_event_type!(
Config,
CreateFileRequest,
FileId,
AttachEvidenceRequest,
DisputeId,
PaymentLinkFormData,
PaymentsRedirectResponseData,
ConfigUpdate
);
#[cfg(feature = "dummy_connector")]
impl_misc_api_event_type!(
DummyConnectorPaymentCompleteRequest,
DummyConnectorPaymentRequest,
DummyConnectorPaymentResponse,
DummyConnectorPaymentRetrieveRequest,
DummyConnectorPaymentConfirmRequest,
DummyConnectorRefundRetrieveRequest,
DummyConnectorRefundResponse,
DummyConnectorRefundRequest
);

View File

@ -305,7 +305,7 @@ Never share your secret api keys. Keep them guarded and secure.
api_models::payment_methods::RequiredFieldInfo,
api_models::refunds::RefundListRequest,
api_models::refunds::RefundListResponse,
api_models::refunds::TimeRange,
api_models::payments::TimeRange,
api_models::mandates::MandateRevokedResponse,
api_models::mandates::MandateResponse,
api_models::mandates::MandateCardDetails,

View File

@ -388,15 +388,15 @@ pub async fn merchant_account_toggle_kv(
json_payload: web::Json<admin::ToggleKVRequest>,
) -> HttpResponse {
let flow = Flow::ConfigKeyUpdate;
let payload = json_payload.into_inner();
let merchant_id = path.into_inner();
let mut payload = json_payload.into_inner();
payload.merchant_id = path.into_inner();
api::server_wrap(
flow,
state,
&req,
(merchant_id, payload),
|state, _, (merchant_id, payload)| kv_for_merchant(state, merchant_id, payload.kv_enabled),
payload,
|state, _, payload| kv_for_merchant(state, payload.merchant_id, payload.kv_enabled),
&auth::AdminApiAuth,
api_locking::LockAction::NotApplicable,
)

View File

@ -124,16 +124,16 @@ pub async fn api_key_update(
) -> impl Responder {
let flow = Flow::ApiKeyUpdate;
let (merchant_id, key_id) = path.into_inner();
let payload = json_payload.into_inner();
let mut payload = json_payload.into_inner();
payload.key_id = key_id;
payload.merchant_id = merchant_id;
api::server_wrap(
flow,
state,
&req,
(&merchant_id, &key_id, payload),
|state, _, (merchant_id, key_id, payload)| {
api_keys::update_api_key(state, merchant_id, key_id, payload)
},
payload,
|state, _, payload| api_keys::update_api_key(state, payload),
&auth::AdminApiAuth,
api_locking::LockAction::NotApplicable,
)

View File

@ -10,7 +10,7 @@ use crate::{
mod consts;
mod core;
mod errors;
mod types;
pub mod types;
mod utils;
#[instrument(skip_all, fields(flow = ?types::Flow::DummyPaymentCreate))]

View File

@ -161,13 +161,14 @@ pub async fn refunds_update(
path: web::Path<String>,
) -> HttpResponse {
let flow = Flow::RefundsUpdate;
let refund_id = path.into_inner();
let mut refund_update_req = json_payload.into_inner();
refund_update_req.refund_id = path.into_inner();
api::server_wrap(
flow,
state,
&req,
json_payload.into_inner(),
|state, auth, req| refund_update_core(state, auth.merchant_account, &refund_id, req),
refund_update_req,
|state, auth, req| refund_update_core(state, auth.merchant_account, req),
&auth::ApiKeyAuth,
api_locking::LockAction::NotApplicable,
)
@ -225,7 +226,7 @@ pub async fn refunds_list(
pub async fn refunds_filter_list(
state: web::Data<AppState>,
req: HttpRequest,
payload: web::Json<api_models::refunds::TimeRange>,
payload: web::Json<api_models::payments::TimeRange>,
) -> HttpResponse {
let flow = Flow::RefundsList;
api::server_wrap(

View File

@ -47,7 +47,7 @@ pub async fn routing_create_config(
pub async fn routing_link_config(
state: web::Data<AppState>,
req: HttpRequest,
path: web::Path<String>,
path: web::Path<routing_types::RoutingAlgorithmId>,
) -> impl Responder {
let flow = Flow::RoutingLinkConfig;
Box::pin(oss_api::server_wrap(
@ -61,7 +61,7 @@ pub async fn routing_link_config(
auth.merchant_account,
#[cfg(not(feature = "business_profile_routing"))]
auth.key_store,
algorithm_id,
algorithm_id.0,
)
},
#[cfg(not(feature = "release"))]
@ -78,7 +78,7 @@ pub async fn routing_link_config(
pub async fn routing_retrieve_config(
state: web::Data<AppState>,
req: HttpRequest,
path: web::Path<String>,
path: web::Path<routing_types::RoutingAlgorithmId>,
) -> impl Responder {
let algorithm_id = path.into_inner();
let flow = Flow::RoutingRetrieveConfig;

View File

@ -22,7 +22,7 @@ pub async fn apple_pay_merchant_registration(
flow,
state,
&req,
json_payload,
json_payload.into_inner(),
|state, _, body| {
verification::verify_merchant_creds_for_applepay(
state.clone(),

View File

@ -34,7 +34,7 @@ use crate::{
errors::{self, CustomResult},
payments,
},
events::api_logs::ApiEvent,
events::api_logs::{ApiEvent, ApiEventMetric, ApiEventsType},
logger,
routes::{
app::AppStateInfo,
@ -769,8 +769,8 @@ where
F: Fn(A, U, T) -> Fut,
'b: 'a,
Fut: Future<Output = CustomResult<ApplicationResponse<Q>, E>>,
Q: Serialize + Debug + 'a,
T: Debug + Serialize,
Q: Serialize + Debug + 'a + ApiEventMetric,
T: Debug + Serialize + ApiEventMetric,
A: AppStateInfo + Clone,
E: ErrorSwitch<OErr> + error_stack::Context,
OErr: ResponseError + error_stack::Context,
@ -791,6 +791,8 @@ where
.attach_printable("Failed to serialize json request")
.change_context(errors::ApiErrorResponse::InternalServerError.switch())?;
let mut event_type = payload.get_api_event_type();
// Currently auth failures are not recorded as API events
let (auth_out, auth_type) = api_auth
.authenticate_and_fetch(request.headers(), &request_state)
@ -838,6 +840,7 @@ where
.change_context(errors::ApiErrorResponse::InternalServerError.switch())?,
);
}
event_type = res.get_api_event_type().or(event_type);
metrics::request::track_response_status_code(res)
}
@ -852,6 +855,7 @@ where
serialized_request,
serialized_response,
auth_type,
event_type.unwrap_or(ApiEventsType::Miscellaneous),
request,
);
match api_event.clone().try_into() {
@ -884,8 +888,8 @@ pub async fn server_wrap<'a, A, T, U, Q, F, Fut, E>(
where
F: Fn(A, U, T) -> Fut,
Fut: Future<Output = CustomResult<ApplicationResponse<Q>, E>>,
Q: Serialize + Debug + 'a,
T: Debug + Serialize,
Q: Serialize + Debug + ApiEventMetric + 'a,
T: Debug + Serialize + ApiEventMetric,
A: AppStateInfo + Clone,
ApplicationResponse<Q>: Debug,
E: ErrorSwitch<api_models::errors::types::ApiErrorResponse> + error_stack::Context,

View File

@ -10,6 +10,12 @@ newtype!(
derives = (Debug, Clone, Serialize)
);
impl common_utils::events::ApiEventMetric for CustomerResponse {
fn get_api_event_type(&self) -> Option<common_utils::events::ApiEventsType> {
self.0.get_api_event_type()
}
}
pub(crate) trait CustomerRequestExt: Sized {
fn validate(self) -> RouterResult<Self>;
}

View File

@ -27,7 +27,7 @@ pub trait RefundDbExt: Sized {
async fn filter_by_meta_constraints(
conn: &PgPooledConn,
merchant_id: &str,
refund_list_details: &api_models::refunds::TimeRange,
refund_list_details: &api_models::payments::TimeRange,
) -> CustomResult<api_models::refunds::RefundListMetaData, errors::DatabaseError>;
async fn get_refunds_count(
@ -114,7 +114,7 @@ impl RefundDbExt for Refund {
async fn filter_by_meta_constraints(
conn: &PgPooledConn,
merchant_id: &str,
refund_list_details: &api_models::refunds::TimeRange,
refund_list_details: &api_models::payments::TimeRange,
) -> CustomResult<api_models::refunds::RefundListMetaData, errors::DatabaseError> {
let start_time = refund_list_details.start_time;

View File

@ -11218,12 +11218,12 @@
"start_time": {
"type": "string",
"format": "date-time",
"description": "The start time to filter refunds list or to get list of filters. To get list of filters start time is needed to be passed"
"description": "The start time to filter payments list or to get list of filters. To get list of filters start time is needed to be passed"
},
"end_time": {
"type": "string",
"format": "date-time",
"description": "The end time to filter refunds list or to get list of filters. If not passed the default time is now",
"description": "The end time to filter payments list or to get list of filters. If not passed the default time is now",
"nullable": true
}
}