mirror of
				https://github.com/juspay/hyperswitch.git
				synced 2025-10-31 18:17:13 +08:00 
			
		
		
		
	 7eb5354efe
			
		
	
	7eb5354efe
	
	
	
		
			
			Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
		
			
				
	
	
		
			2142 lines
		
	
	
		
			85 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			2142 lines
		
	
	
		
			85 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| pub use analytics::*;
 | |
| 
 | |
| pub mod routes {
 | |
|     use actix_web::{web, Responder, Scope};
 | |
|     use analytics::{
 | |
|         api_event::api_events_core, connector_events::connector_events_core, enums::AuthInfo,
 | |
|         errors::AnalyticsError, lambda_utils::invoke_lambda, opensearch::OpenSearchError,
 | |
|         outgoing_webhook_event::outgoing_webhook_events_core, sdk_events::sdk_events_core,
 | |
|         AnalyticsFlow,
 | |
|     };
 | |
|     use api_models::analytics::{
 | |
|         api_event::QueryType,
 | |
|         search::{
 | |
|             GetGlobalSearchRequest, GetSearchRequest, GetSearchRequestWithIndex, SearchIndex,
 | |
|         },
 | |
|         GenerateReportRequest, GetActivePaymentsMetricRequest, GetApiEventFiltersRequest,
 | |
|         GetApiEventMetricRequest, GetAuthEventMetricRequest, GetDisputeMetricRequest,
 | |
|         GetFrmFilterRequest, GetFrmMetricRequest, GetPaymentFiltersRequest,
 | |
|         GetPaymentIntentFiltersRequest, GetPaymentIntentMetricRequest, GetPaymentMetricRequest,
 | |
|         GetRefundFilterRequest, GetRefundMetricRequest, GetSdkEventFiltersRequest,
 | |
|         GetSdkEventMetricRequest, ReportRequest,
 | |
|     };
 | |
|     use common_enums::EntityType;
 | |
|     use common_utils::id_type::{MerchantId, OrganizationId};
 | |
|     use error_stack::{report, ResultExt};
 | |
| 
 | |
|     use crate::{
 | |
|         consts::opensearch::OPENSEARCH_INDEX_PERMISSIONS,
 | |
|         core::{api_locking, errors::user::UserErrors, verification::utils},
 | |
|         db::user::UserInterface,
 | |
|         routes::AppState,
 | |
|         services::{
 | |
|             api,
 | |
|             authentication::{self as auth, AuthenticationData, UserFromToken},
 | |
|             authorization::{permissions::Permission, roles::RoleInfo},
 | |
|             ApplicationResponse,
 | |
|         },
 | |
|         types::domain::UserEmail,
 | |
|     };
 | |
| 
 | |
|     pub struct Analytics;
 | |
| 
 | |
|     impl Analytics {
 | |
|         pub fn server(state: AppState) -> Scope {
 | |
|             web::scope("/analytics")
 | |
|                 .app_data(web::Data::new(state))
 | |
|                 .service(
 | |
|                     web::scope("/v1")
 | |
|                         .service(
 | |
|                             web::resource("metrics/payments")
 | |
|                                 .route(web::post().to(get_merchant_payment_metrics)),
 | |
|                         )
 | |
|                         .service(
 | |
|                             web::resource("metrics/refunds")
 | |
|                                 .route(web::post().to(get_merchant_refund_metrics)),
 | |
|                         )
 | |
|                         .service(
 | |
|                             web::resource("filters/payments")
 | |
|                                 .route(web::post().to(get_merchant_payment_filters)),
 | |
|                         )
 | |
|                         .service(
 | |
|                             web::resource("filters/frm").route(web::post().to(get_frm_filters)),
 | |
|                         )
 | |
|                         .service(
 | |
|                             web::resource("filters/refunds")
 | |
|                                 .route(web::post().to(get_merchant_refund_filters)),
 | |
|                         )
 | |
|                         .service(web::resource("{domain}/info").route(web::get().to(get_info)))
 | |
|                         .service(
 | |
|                             web::resource("report/dispute")
 | |
|                                 .route(web::post().to(generate_merchant_dispute_report)),
 | |
|                         )
 | |
|                         .service(
 | |
|                             web::resource("report/refunds")
 | |
|                                 .route(web::post().to(generate_merchant_refund_report)),
 | |
|                         )
 | |
|                         .service(
 | |
|                             web::resource("report/payments")
 | |
|                                 .route(web::post().to(generate_merchant_payment_report)),
 | |
|                         )
 | |
|                         .service(
 | |
|                             web::resource("metrics/sdk_events")
 | |
|                                 .route(web::post().to(get_sdk_event_metrics)),
 | |
|                         )
 | |
|                         .service(
 | |
|                             web::resource("metrics/active_payments")
 | |
|                                 .route(web::post().to(get_active_payments_metrics)),
 | |
|                         )
 | |
|                         .service(
 | |
|                             web::resource("filters/sdk_events")
 | |
|                                 .route(web::post().to(get_sdk_event_filters)),
 | |
|                         )
 | |
|                         .service(
 | |
|                             web::resource("metrics/auth_events")
 | |
|                                 .route(web::post().to(get_auth_event_metrics)),
 | |
|                         )
 | |
|                         .service(
 | |
|                             web::resource("metrics/frm").route(web::post().to(get_frm_metrics)),
 | |
|                         )
 | |
|                         .service(
 | |
|                             web::resource("api_event_logs")
 | |
|                                 .route(web::get().to(get_profile_api_events)),
 | |
|                         )
 | |
|                         .service(
 | |
|                             web::resource("sdk_event_logs")
 | |
|                                 .route(web::post().to(get_profile_sdk_events)),
 | |
|                         )
 | |
|                         .service(
 | |
|                             web::resource("connector_event_logs")
 | |
|                                 .route(web::get().to(get_profile_connector_events)),
 | |
|                         )
 | |
|                         .service(
 | |
|                             web::resource("outgoing_webhook_event_logs")
 | |
|                                 .route(web::get().to(get_profile_outgoing_webhook_events)),
 | |
|                         )
 | |
|                         .service(
 | |
|                             web::resource("metrics/api_events")
 | |
|                                 .route(web::post().to(get_merchant_api_events_metrics)),
 | |
|                         )
 | |
|                         .service(
 | |
|                             web::resource("filters/api_events")
 | |
|                                 .route(web::post().to(get_merchant_api_event_filters)),
 | |
|                         )
 | |
|                         .service(
 | |
|                             web::resource("search")
 | |
|                                 .route(web::post().to(get_global_search_results)),
 | |
|                         )
 | |
|                         .service(
 | |
|                             web::resource("search/{domain}")
 | |
|                                 .route(web::post().to(get_search_results)),
 | |
|                         )
 | |
|                         .service(
 | |
|                             web::resource("metrics/disputes")
 | |
|                                 .route(web::post().to(get_merchant_dispute_metrics)),
 | |
|                         )
 | |
|                         .service(
 | |
|                             web::resource("filters/disputes")
 | |
|                                 .route(web::post().to(get_merchant_dispute_filters)),
 | |
|                         )
 | |
|                         .service(
 | |
|                             web::scope("/merchant")
 | |
|                                 .service(
 | |
|                                     web::resource("metrics/payments")
 | |
|                                         .route(web::post().to(get_merchant_payment_metrics)),
 | |
|                                 )
 | |
|                                 .service(
 | |
|                                     web::resource("metrics/refunds")
 | |
|                                         .route(web::post().to(get_merchant_refund_metrics)),
 | |
|                                 )
 | |
|                                 .service(
 | |
|                                     web::resource("filters/payments")
 | |
|                                         .route(web::post().to(get_merchant_payment_filters)),
 | |
|                                 )
 | |
|                                 .service(
 | |
|                                     web::resource("filters/refunds")
 | |
|                                         .route(web::post().to(get_merchant_refund_filters)),
 | |
|                                 )
 | |
|                                 .service(
 | |
|                                     web::resource("{domain}/info").route(web::get().to(get_info)),
 | |
|                                 )
 | |
|                                 .service(
 | |
|                                     web::resource("report/dispute")
 | |
|                                         .route(web::post().to(generate_merchant_dispute_report)),
 | |
|                                 )
 | |
|                                 .service(
 | |
|                                     web::resource("report/refunds")
 | |
|                                         .route(web::post().to(generate_merchant_refund_report)),
 | |
|                                 )
 | |
|                                 .service(
 | |
|                                     web::resource("report/payments")
 | |
|                                         .route(web::post().to(generate_merchant_payment_report)),
 | |
|                                 )
 | |
|                                 .service(
 | |
|                                     web::resource("metrics/api_events")
 | |
|                                         .route(web::post().to(get_merchant_api_events_metrics)),
 | |
|                                 )
 | |
|                                 .service(
 | |
|                                     web::resource("filters/api_events")
 | |
|                                         .route(web::post().to(get_merchant_api_event_filters)),
 | |
|                                 )
 | |
|                                 .service(
 | |
|                                     web::resource("metrics/disputes")
 | |
|                                         .route(web::post().to(get_merchant_dispute_metrics)),
 | |
|                                 )
 | |
|                                 .service(
 | |
|                                     web::resource("filters/disputes")
 | |
|                                         .route(web::post().to(get_merchant_dispute_filters)),
 | |
|                                 ),
 | |
|                         )
 | |
|                         .service(
 | |
|                             web::scope("/org")
 | |
|                                 .service(
 | |
|                                     web::resource("{domain}/info").route(web::get().to(get_info)),
 | |
|                                 )
 | |
|                                 .service(
 | |
|                                     web::resource("metrics/payments")
 | |
|                                         .route(web::post().to(get_org_payment_metrics)),
 | |
|                                 )
 | |
|                                 .service(
 | |
|                                     web::resource("filters/payments")
 | |
|                                         .route(web::post().to(get_org_payment_filters)),
 | |
|                                 )
 | |
|                                 .service(
 | |
|                                     web::resource("metrics/refunds")
 | |
|                                         .route(web::post().to(get_org_refund_metrics)),
 | |
|                                 )
 | |
|                                 .service(
 | |
|                                     web::resource("filters/refunds")
 | |
|                                         .route(web::post().to(get_org_refund_filters)),
 | |
|                                 )
 | |
|                                 .service(
 | |
|                                     web::resource("metrics/disputes")
 | |
|                                         .route(web::post().to(get_org_dispute_metrics)),
 | |
|                                 )
 | |
|                                 .service(
 | |
|                                     web::resource("filters/disputes")
 | |
|                                         .route(web::post().to(get_org_dispute_filters)),
 | |
|                                 )
 | |
|                                 .service(
 | |
|                                     web::resource("report/dispute")
 | |
|                                         .route(web::post().to(generate_org_dispute_report)),
 | |
|                                 )
 | |
|                                 .service(
 | |
|                                     web::resource("report/refunds")
 | |
|                                         .route(web::post().to(generate_org_refund_report)),
 | |
|                                 )
 | |
|                                 .service(
 | |
|                                     web::resource("report/payments")
 | |
|                                         .route(web::post().to(generate_org_payment_report)),
 | |
|                                 ),
 | |
|                         )
 | |
|                         .service(
 | |
|                             web::scope("/profile")
 | |
|                                 .service(
 | |
|                                     web::resource("{domain}/info").route(web::get().to(get_info)),
 | |
|                                 )
 | |
|                                 .service(
 | |
|                                     web::resource("metrics/payments")
 | |
|                                         .route(web::post().to(get_profile_payment_metrics)),
 | |
|                                 )
 | |
|                                 .service(
 | |
|                                     web::resource("filters/payments")
 | |
|                                         .route(web::post().to(get_profile_payment_filters)),
 | |
|                                 )
 | |
|                                 .service(
 | |
|                                     web::resource("metrics/refunds")
 | |
|                                         .route(web::post().to(get_profile_refund_metrics)),
 | |
|                                 )
 | |
|                                 .service(
 | |
|                                     web::resource("filters/refunds")
 | |
|                                         .route(web::post().to(get_profile_refund_filters)),
 | |
|                                 )
 | |
|                                 .service(
 | |
|                                     web::resource("metrics/disputes")
 | |
|                                         .route(web::post().to(get_profile_dispute_metrics)),
 | |
|                                 )
 | |
|                                 .service(
 | |
|                                     web::resource("filters/disputes")
 | |
|                                         .route(web::post().to(get_profile_dispute_filters)),
 | |
|                                 )
 | |
|                                 .service(
 | |
|                                     web::resource("connector_event_logs")
 | |
|                                         .route(web::get().to(get_profile_connector_events)),
 | |
|                                 )
 | |
|                                 .service(
 | |
|                                     web::resource("outgoing_webhook_event_logs")
 | |
|                                         .route(web::get().to(get_profile_outgoing_webhook_events)),
 | |
|                                 )
 | |
|                                 .service(
 | |
|                                     web::resource("report/dispute")
 | |
|                                         .route(web::post().to(generate_profile_dispute_report)),
 | |
|                                 )
 | |
|                                 .service(
 | |
|                                     web::resource("report/refunds")
 | |
|                                         .route(web::post().to(generate_profile_refund_report)),
 | |
|                                 )
 | |
|                                 .service(
 | |
|                                     web::resource("report/payments")
 | |
|                                         .route(web::post().to(generate_profile_payment_report)),
 | |
|                                 )
 | |
|                                 .service(
 | |
|                                     web::resource("api_event_logs")
 | |
|                                         .route(web::get().to(get_profile_api_events)),
 | |
|                                 )
 | |
|                                 .service(
 | |
|                                     web::resource("sdk_event_logs")
 | |
|                                         .route(web::post().to(get_profile_sdk_events)),
 | |
|                                 ),
 | |
|                         ),
 | |
|                 )
 | |
|                 .service(
 | |
|                     web::scope("/v2")
 | |
|                         .service(
 | |
|                             web::resource("/metrics/payments")
 | |
|                                 .route(web::post().to(get_merchant_payment_intent_metrics)),
 | |
|                         )
 | |
|                         .service(
 | |
|                             web::resource("/filters/payments")
 | |
|                                 .route(web::post().to(get_payment_intents_filters)),
 | |
|                         )
 | |
|                         .service(
 | |
|                             web::scope("/merchant")
 | |
|                                 .service(
 | |
|                                     web::resource("/metrics/payments")
 | |
|                                         .route(web::post().to(get_merchant_payment_intent_metrics)),
 | |
|                                 )
 | |
|                                 .service(
 | |
|                                     web::resource("/filters/payments")
 | |
|                                         .route(web::post().to(get_payment_intents_filters)),
 | |
|                                 ),
 | |
|                         )
 | |
|                         .service(
 | |
|                             web::scope("/org").service(
 | |
|                                 web::resource("/metrics/payments")
 | |
|                                     .route(web::post().to(get_org_payment_intent_metrics)),
 | |
|                             ),
 | |
|                         )
 | |
|                         .service(
 | |
|                             web::scope("/profile").service(
 | |
|                                 web::resource("/metrics/payments")
 | |
|                                     .route(web::post().to(get_profile_payment_intent_metrics)),
 | |
|                             ),
 | |
|                         ),
 | |
|                 )
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     pub async fn get_info(
 | |
|         state: web::Data<AppState>,
 | |
|         req: actix_web::HttpRequest,
 | |
|         domain: web::Path<analytics::AnalyticsDomain>,
 | |
|     ) -> impl Responder {
 | |
|         let flow = AnalyticsFlow::GetInfo;
 | |
|         Box::pin(api::server_wrap(
 | |
|             flow,
 | |
|             state,
 | |
|             &req,
 | |
|             domain.into_inner(),
 | |
|             |_, _: (), domain: analytics::AnalyticsDomain, _| async {
 | |
|                 analytics::core::get_domain_info(domain)
 | |
|                     .await
 | |
|                     .map(ApplicationResponse::Json)
 | |
|             },
 | |
|             &auth::NoAuth,
 | |
|             api_locking::LockAction::NotApplicable,
 | |
|         ))
 | |
|         .await
 | |
|     }
 | |
| 
 | |
|     /// # Panics
 | |
|     ///
 | |
|     /// Panics if `json_payload` array does not contain one `GetPaymentMetricRequest` element.
 | |
|     pub async fn get_merchant_payment_metrics(
 | |
|         state: web::Data<AppState>,
 | |
|         req: actix_web::HttpRequest,
 | |
|         json_payload: web::Json<[GetPaymentMetricRequest; 1]>,
 | |
|     ) -> impl Responder {
 | |
|         // safety: This shouldn't panic owing to the data type
 | |
|         #[allow(clippy::expect_used)]
 | |
|         let payload = json_payload
 | |
|             .into_inner()
 | |
|             .to_vec()
 | |
|             .pop()
 | |
|             .expect("Couldn't get GetPaymentMetricRequest");
 | |
|         let flow = AnalyticsFlow::GetPaymentMetrics;
 | |
|         Box::pin(api::server_wrap(
 | |
|             flow,
 | |
|             state,
 | |
|             &req,
 | |
|             payload,
 | |
|             |state, auth: AuthenticationData, req, _| async move {
 | |
|                 let org_id = auth.merchant_account.get_org_id();
 | |
|                 let merchant_id = auth.merchant_account.get_id();
 | |
|                 let auth: AuthInfo = AuthInfo::MerchantLevel {
 | |
|                     org_id: org_id.clone(),
 | |
|                     merchant_ids: vec![merchant_id.clone()],
 | |
|                 };
 | |
|                 analytics::payments::get_metrics(&state.pool, &auth, req)
 | |
|                     .await
 | |
|                     .map(ApplicationResponse::Json)
 | |
|             },
 | |
|             &auth::JWTAuth {
 | |
|                 permission: Permission::Analytics,
 | |
|                 minimum_entity_level: EntityType::Merchant,
 | |
|             },
 | |
|             api_locking::LockAction::NotApplicable,
 | |
|         ))
 | |
|         .await
 | |
|     }
 | |
| 
 | |
|     /// # Panics
 | |
|     ///
 | |
|     /// Panics if `json_payload` array does not contain one `GetPaymentMetricRequest` element.
 | |
|     pub async fn get_org_payment_metrics(
 | |
|         state: web::Data<AppState>,
 | |
|         req: actix_web::HttpRequest,
 | |
|         json_payload: web::Json<[GetPaymentMetricRequest; 1]>,
 | |
|     ) -> impl Responder {
 | |
|         // safety: This shouldn't panic owing to the data type
 | |
|         #[allow(clippy::expect_used)]
 | |
|         let payload = json_payload
 | |
|             .into_inner()
 | |
|             .to_vec()
 | |
|             .pop()
 | |
|             .expect("Couldn't get GetPaymentMetricRequest");
 | |
|         let flow = AnalyticsFlow::GetPaymentMetrics;
 | |
|         Box::pin(api::server_wrap(
 | |
|             flow,
 | |
|             state,
 | |
|             &req,
 | |
|             payload,
 | |
|             |state, auth: AuthenticationData, req, _| async move {
 | |
|                 let org_id = auth.merchant_account.get_org_id();
 | |
|                 let auth: AuthInfo = AuthInfo::OrgLevel {
 | |
|                     org_id: org_id.clone(),
 | |
|                 };
 | |
|                 analytics::payments::get_metrics(&state.pool, &auth, req)
 | |
|                     .await
 | |
|                     .map(ApplicationResponse::Json)
 | |
|             },
 | |
|             &auth::JWTAuth {
 | |
|                 permission: Permission::Analytics,
 | |
|                 minimum_entity_level: EntityType::Organization,
 | |
|             },
 | |
|             api_locking::LockAction::NotApplicable,
 | |
|         ))
 | |
|         .await
 | |
|     }
 | |
| 
 | |
|     /// # Panics
 | |
|     ///
 | |
|     /// Panics if `json_payload` array does not contain one `GetPaymentMetricRequest` element.
 | |
|     pub async fn get_profile_payment_metrics(
 | |
|         state: web::Data<AppState>,
 | |
|         req: actix_web::HttpRequest,
 | |
|         json_payload: web::Json<[GetPaymentMetricRequest; 1]>,
 | |
|     ) -> impl Responder {
 | |
|         // safety: This shouldn't panic owing to the data type
 | |
|         #[allow(clippy::expect_used)]
 | |
|         let payload = json_payload
 | |
|             .into_inner()
 | |
|             .to_vec()
 | |
|             .pop()
 | |
|             .expect("Couldn't get GetPaymentMetricRequest");
 | |
|         let flow = AnalyticsFlow::GetPaymentMetrics;
 | |
|         Box::pin(api::server_wrap(
 | |
|             flow,
 | |
|             state,
 | |
|             &req,
 | |
|             payload,
 | |
|             |state, auth: AuthenticationData, req, _| async move {
 | |
|                 let org_id = auth.merchant_account.get_org_id();
 | |
|                 let merchant_id = auth.merchant_account.get_id();
 | |
|                 let profile_id = auth
 | |
|                     .profile_id
 | |
|                     .ok_or(report!(UserErrors::JwtProfileIdMissing))
 | |
|                     .change_context(AnalyticsError::AccessForbiddenError)?;
 | |
|                 let auth: AuthInfo = AuthInfo::ProfileLevel {
 | |
|                     org_id: org_id.clone(),
 | |
|                     merchant_id: merchant_id.clone(),
 | |
|                     profile_ids: vec![profile_id.clone()],
 | |
|                 };
 | |
|                 analytics::payments::get_metrics(&state.pool, &auth, req)
 | |
|                     .await
 | |
|                     .map(ApplicationResponse::Json)
 | |
|             },
 | |
|             &auth::JWTAuth {
 | |
|                 permission: Permission::Analytics,
 | |
|                 minimum_entity_level: EntityType::Profile,
 | |
|             },
 | |
|             api_locking::LockAction::NotApplicable,
 | |
|         ))
 | |
|         .await
 | |
|     }
 | |
| 
 | |
|     /// # Panics
 | |
|     ///
 | |
|     /// Panics if `json_payload` array does not contain one `GetPaymentIntentMetricRequest` element.
 | |
|     pub async fn get_merchant_payment_intent_metrics(
 | |
|         state: web::Data<AppState>,
 | |
|         req: actix_web::HttpRequest,
 | |
|         json_payload: web::Json<[GetPaymentIntentMetricRequest; 1]>,
 | |
|     ) -> impl Responder {
 | |
|         // safety: This shouldn't panic owing to the data type
 | |
|         #[allow(clippy::expect_used)]
 | |
|         let payload = json_payload
 | |
|             .into_inner()
 | |
|             .to_vec()
 | |
|             .pop()
 | |
|             .expect("Couldn't get GetPaymentIntentMetricRequest");
 | |
|         let flow = AnalyticsFlow::GetPaymentIntentMetrics;
 | |
|         Box::pin(api::server_wrap(
 | |
|             flow,
 | |
|             state,
 | |
|             &req,
 | |
|             payload,
 | |
|             |state, auth: AuthenticationData, req, _| async move {
 | |
|                 let org_id = auth.merchant_account.get_org_id();
 | |
|                 let merchant_id = auth.merchant_account.get_id();
 | |
|                 let auth: AuthInfo = AuthInfo::MerchantLevel {
 | |
|                     org_id: org_id.clone(),
 | |
|                     merchant_ids: vec![merchant_id.clone()],
 | |
|                 };
 | |
|                 analytics::payment_intents::get_metrics(&state.pool, &auth, req)
 | |
|                     .await
 | |
|                     .map(ApplicationResponse::Json)
 | |
|             },
 | |
|             &auth::JWTAuth {
 | |
|                 permission: Permission::Analytics,
 | |
|                 minimum_entity_level: EntityType::Merchant,
 | |
|             },
 | |
|             api_locking::LockAction::NotApplicable,
 | |
|         ))
 | |
|         .await
 | |
|     }
 | |
| 
 | |
|     /// # Panics
 | |
|     ///
 | |
|     /// Panics if `json_payload` array does not contain one `GetPaymentIntentMetricRequest` element.
 | |
|     pub async fn get_org_payment_intent_metrics(
 | |
|         state: web::Data<AppState>,
 | |
|         req: actix_web::HttpRequest,
 | |
|         json_payload: web::Json<[GetPaymentIntentMetricRequest; 1]>,
 | |
|     ) -> impl Responder {
 | |
|         // safety: This shouldn't panic owing to the data type
 | |
|         #[allow(clippy::expect_used)]
 | |
|         let payload = json_payload
 | |
|             .into_inner()
 | |
|             .to_vec()
 | |
|             .pop()
 | |
|             .expect("Couldn't get GetPaymentIntentMetricRequest");
 | |
|         let flow = AnalyticsFlow::GetPaymentIntentMetrics;
 | |
|         Box::pin(api::server_wrap(
 | |
|             flow,
 | |
|             state,
 | |
|             &req,
 | |
|             payload,
 | |
|             |state, auth: AuthenticationData, req, _| async move {
 | |
|                 let org_id = auth.merchant_account.get_org_id();
 | |
|                 let auth: AuthInfo = AuthInfo::OrgLevel {
 | |
|                     org_id: org_id.clone(),
 | |
|                 };
 | |
|                 analytics::payment_intents::get_metrics(&state.pool, &auth, req)
 | |
|                     .await
 | |
|                     .map(ApplicationResponse::Json)
 | |
|             },
 | |
|             &auth::JWTAuth {
 | |
|                 permission: Permission::Analytics,
 | |
|                 minimum_entity_level: EntityType::Organization,
 | |
|             },
 | |
|             api_locking::LockAction::NotApplicable,
 | |
|         ))
 | |
|         .await
 | |
|     }
 | |
| 
 | |
|     /// # Panics
 | |
|     ///
 | |
|     /// Panics if `json_payload` array does not contain one `GetPaymentIntentMetricRequest` element.
 | |
|     pub async fn get_profile_payment_intent_metrics(
 | |
|         state: web::Data<AppState>,
 | |
|         req: actix_web::HttpRequest,
 | |
|         json_payload: web::Json<[GetPaymentIntentMetricRequest; 1]>,
 | |
|     ) -> impl Responder {
 | |
|         // safety: This shouldn't panic owing to the data type
 | |
|         #[allow(clippy::expect_used)]
 | |
|         let payload = json_payload
 | |
|             .into_inner()
 | |
|             .to_vec()
 | |
|             .pop()
 | |
|             .expect("Couldn't get GetPaymentIntentMetricRequest");
 | |
|         let flow = AnalyticsFlow::GetPaymentIntentMetrics;
 | |
|         Box::pin(api::server_wrap(
 | |
|             flow,
 | |
|             state,
 | |
|             &req,
 | |
|             payload,
 | |
|             |state, auth: AuthenticationData, req, _| async move {
 | |
|                 let org_id = auth.merchant_account.get_org_id();
 | |
|                 let merchant_id = auth.merchant_account.get_id();
 | |
|                 let profile_id = auth
 | |
|                     .profile_id
 | |
|                     .ok_or(report!(UserErrors::JwtProfileIdMissing))
 | |
|                     .change_context(AnalyticsError::AccessForbiddenError)?;
 | |
|                 let auth: AuthInfo = AuthInfo::ProfileLevel {
 | |
|                     org_id: org_id.clone(),
 | |
|                     merchant_id: merchant_id.clone(),
 | |
|                     profile_ids: vec![profile_id.clone()],
 | |
|                 };
 | |
|                 analytics::payment_intents::get_metrics(&state.pool, &auth, req)
 | |
|                     .await
 | |
|                     .map(ApplicationResponse::Json)
 | |
|             },
 | |
|             &auth::JWTAuth {
 | |
|                 permission: Permission::Analytics,
 | |
|                 minimum_entity_level: EntityType::Profile,
 | |
|             },
 | |
|             api_locking::LockAction::NotApplicable,
 | |
|         ))
 | |
|         .await
 | |
|     }
 | |
| 
 | |
|     /// # Panics
 | |
|     ///
 | |
|     /// Panics if `json_payload` array does not contain one `GetRefundMetricRequest` element.
 | |
|     pub async fn get_merchant_refund_metrics(
 | |
|         state: web::Data<AppState>,
 | |
|         req: actix_web::HttpRequest,
 | |
|         json_payload: web::Json<[GetRefundMetricRequest; 1]>,
 | |
|     ) -> impl Responder {
 | |
|         #[allow(clippy::expect_used)]
 | |
|         // safety: This shouldn't panic owing to the data type
 | |
|         let payload = json_payload
 | |
|             .into_inner()
 | |
|             .to_vec()
 | |
|             .pop()
 | |
|             .expect("Couldn't get GetRefundMetricRequest");
 | |
|         let flow = AnalyticsFlow::GetRefundsMetrics;
 | |
|         Box::pin(api::server_wrap(
 | |
|             flow,
 | |
|             state,
 | |
|             &req,
 | |
|             payload,
 | |
|             |state, auth: AuthenticationData, req, _| async move {
 | |
|                 let org_id = auth.merchant_account.get_org_id();
 | |
|                 let merchant_id = auth.merchant_account.get_id();
 | |
|                 let auth: AuthInfo = AuthInfo::MerchantLevel {
 | |
|                     org_id: org_id.clone(),
 | |
|                     merchant_ids: vec![merchant_id.clone()],
 | |
|                 };
 | |
|                 analytics::refunds::get_metrics(&state.pool, &auth, req)
 | |
|                     .await
 | |
|                     .map(ApplicationResponse::Json)
 | |
|             },
 | |
|             &auth::JWTAuth {
 | |
|                 permission: Permission::Analytics,
 | |
|                 minimum_entity_level: EntityType::Merchant,
 | |
|             },
 | |
|             api_locking::LockAction::NotApplicable,
 | |
|         ))
 | |
|         .await
 | |
|     }
 | |
| 
 | |
|     /// # Panics
 | |
|     ///
 | |
|     /// Panics if `json_payload` array does not contain one `GetRefundMetricRequest` element.
 | |
|     pub async fn get_org_refund_metrics(
 | |
|         state: web::Data<AppState>,
 | |
|         req: actix_web::HttpRequest,
 | |
|         json_payload: web::Json<[GetRefundMetricRequest; 1]>,
 | |
|     ) -> impl Responder {
 | |
|         #[allow(clippy::expect_used)]
 | |
|         // safety: This shouldn't panic owing to the data type
 | |
|         let payload = json_payload
 | |
|             .into_inner()
 | |
|             .to_vec()
 | |
|             .pop()
 | |
|             .expect("Couldn't get GetRefundMetricRequest");
 | |
|         let flow = AnalyticsFlow::GetRefundsMetrics;
 | |
|         Box::pin(api::server_wrap(
 | |
|             flow,
 | |
|             state,
 | |
|             &req,
 | |
|             payload,
 | |
|             |state, auth: AuthenticationData, req, _| async move {
 | |
|                 let org_id = auth.merchant_account.get_org_id();
 | |
|                 let auth: AuthInfo = AuthInfo::OrgLevel {
 | |
|                     org_id: org_id.clone(),
 | |
|                 };
 | |
|                 analytics::refunds::get_metrics(&state.pool, &auth, req)
 | |
|                     .await
 | |
|                     .map(ApplicationResponse::Json)
 | |
|             },
 | |
|             &auth::JWTAuth {
 | |
|                 permission: Permission::Analytics,
 | |
|                 minimum_entity_level: EntityType::Organization,
 | |
|             },
 | |
|             api_locking::LockAction::NotApplicable,
 | |
|         ))
 | |
|         .await
 | |
|     }
 | |
| 
 | |
|     /// # Panics
 | |
|     ///
 | |
|     /// Panics if `json_payload` array does not contain one `GetRefundMetricRequest` element.
 | |
|     pub async fn get_profile_refund_metrics(
 | |
|         state: web::Data<AppState>,
 | |
|         req: actix_web::HttpRequest,
 | |
|         json_payload: web::Json<[GetRefundMetricRequest; 1]>,
 | |
|     ) -> impl Responder {
 | |
|         #[allow(clippy::expect_used)]
 | |
|         // safety: This shouldn't panic owing to the data type
 | |
|         let payload = json_payload
 | |
|             .into_inner()
 | |
|             .to_vec()
 | |
|             .pop()
 | |
|             .expect("Couldn't get GetRefundMetricRequest");
 | |
|         let flow = AnalyticsFlow::GetRefundsMetrics;
 | |
|         Box::pin(api::server_wrap(
 | |
|             flow,
 | |
|             state,
 | |
|             &req,
 | |
|             payload,
 | |
|             |state, auth: AuthenticationData, req, _| async move {
 | |
|                 let org_id = auth.merchant_account.get_org_id();
 | |
|                 let merchant_id = auth.merchant_account.get_id();
 | |
|                 let profile_id = auth
 | |
|                     .profile_id
 | |
|                     .ok_or(report!(UserErrors::JwtProfileIdMissing))
 | |
|                     .change_context(AnalyticsError::AccessForbiddenError)?;
 | |
|                 let auth: AuthInfo = AuthInfo::ProfileLevel {
 | |
|                     org_id: org_id.clone(),
 | |
|                     merchant_id: merchant_id.clone(),
 | |
|                     profile_ids: vec![profile_id.clone()],
 | |
|                 };
 | |
|                 analytics::refunds::get_metrics(&state.pool, &auth, req)
 | |
|                     .await
 | |
|                     .map(ApplicationResponse::Json)
 | |
|             },
 | |
|             &auth::JWTAuth {
 | |
|                 permission: Permission::Analytics,
 | |
|                 minimum_entity_level: EntityType::Profile,
 | |
|             },
 | |
|             api_locking::LockAction::NotApplicable,
 | |
|         ))
 | |
|         .await
 | |
|     }
 | |
| 
 | |
|     /// # Panics
 | |
|     ///
 | |
|     /// Panics if `json_payload` array does not contain one `GetFrmMetricRequest` element.
 | |
|     pub async fn get_frm_metrics(
 | |
|         state: web::Data<AppState>,
 | |
|         req: actix_web::HttpRequest,
 | |
|         json_payload: web::Json<[GetFrmMetricRequest; 1]>,
 | |
|     ) -> impl Responder {
 | |
|         #[allow(clippy::expect_used)]
 | |
|         // safety: This shouldn't panic owing to the data type
 | |
|         let payload = json_payload
 | |
|             .into_inner()
 | |
|             .to_vec()
 | |
|             .pop()
 | |
|             .expect("Couldn't get GetFrmMetricRequest");
 | |
|         let flow = AnalyticsFlow::GetFrmMetrics;
 | |
|         Box::pin(api::server_wrap(
 | |
|             flow,
 | |
|             state,
 | |
|             &req,
 | |
|             payload,
 | |
|             |state, auth: AuthenticationData, req, _| async move {
 | |
|                 analytics::frm::get_metrics(&state.pool, auth.merchant_account.get_id(), req)
 | |
|                     .await
 | |
|                     .map(ApplicationResponse::Json)
 | |
|             },
 | |
|             &auth::JWTAuth {
 | |
|                 permission: Permission::Analytics,
 | |
|                 minimum_entity_level: EntityType::Merchant,
 | |
|             },
 | |
|             api_locking::LockAction::NotApplicable,
 | |
|         ))
 | |
|         .await
 | |
|     }
 | |
| 
 | |
|     /// # Panics
 | |
|     ///
 | |
|     /// Panics if `json_payload` array does not contain one `GetSdkEventMetricRequest` element.
 | |
|     pub async fn get_sdk_event_metrics(
 | |
|         state: web::Data<AppState>,
 | |
|         req: actix_web::HttpRequest,
 | |
|         json_payload: web::Json<[GetSdkEventMetricRequest; 1]>,
 | |
|     ) -> impl Responder {
 | |
|         // safety: This shouldn't panic owing to the data type
 | |
|         #[allow(clippy::expect_used)]
 | |
|         let payload = json_payload
 | |
|             .into_inner()
 | |
|             .to_vec()
 | |
|             .pop()
 | |
|             .expect("Couldn't get GetSdkEventMetricRequest");
 | |
|         let flow = AnalyticsFlow::GetSdkMetrics;
 | |
|         Box::pin(api::server_wrap(
 | |
|             flow,
 | |
|             state,
 | |
|             &req,
 | |
|             payload,
 | |
|             |state, auth: AuthenticationData, req, _| async move {
 | |
|                 analytics::sdk_events::get_metrics(
 | |
|                     &state.pool,
 | |
|                     &auth.merchant_account.publishable_key,
 | |
|                     req,
 | |
|                 )
 | |
|                 .await
 | |
|                 .map(ApplicationResponse::Json)
 | |
|             },
 | |
|             &auth::JWTAuth {
 | |
|                 permission: Permission::Analytics,
 | |
|                 minimum_entity_level: EntityType::Merchant,
 | |
|             },
 | |
|             api_locking::LockAction::NotApplicable,
 | |
|         ))
 | |
|         .await
 | |
|     }
 | |
| 
 | |
|     /// # Panics
 | |
|     ///
 | |
|     /// Panics if `json_payload` array does not contain one `GetActivePaymentsMetricRequest` element.
 | |
|     pub async fn get_active_payments_metrics(
 | |
|         state: web::Data<AppState>,
 | |
|         req: actix_web::HttpRequest,
 | |
|         json_payload: web::Json<[GetActivePaymentsMetricRequest; 1]>,
 | |
|     ) -> impl Responder {
 | |
|         // safety: This shouldn't panic owing to the data type
 | |
|         #[allow(clippy::expect_used)]
 | |
|         let payload = json_payload
 | |
|             .into_inner()
 | |
|             .to_vec()
 | |
|             .pop()
 | |
|             .expect("Couldn't get GetActivePaymentsMetricRequest");
 | |
|         let flow = AnalyticsFlow::GetActivePaymentsMetrics;
 | |
|         Box::pin(api::server_wrap(
 | |
|             flow,
 | |
|             state,
 | |
|             &req,
 | |
|             payload,
 | |
|             |state, auth: AuthenticationData, req, _| async move {
 | |
|                 analytics::active_payments::get_metrics(
 | |
|                     &state.pool,
 | |
|                     &auth.merchant_account.publishable_key,
 | |
|                     auth.merchant_account.get_id(),
 | |
|                     req,
 | |
|                 )
 | |
|                 .await
 | |
|                 .map(ApplicationResponse::Json)
 | |
|             },
 | |
|             &auth::JWTAuth {
 | |
|                 permission: Permission::Analytics,
 | |
|                 minimum_entity_level: EntityType::Merchant,
 | |
|             },
 | |
|             api_locking::LockAction::NotApplicable,
 | |
|         ))
 | |
|         .await
 | |
|     }
 | |
| 
 | |
|     /// # Panics
 | |
|     ///
 | |
|     /// Panics if `json_payload` array does not contain one `GetAuthEventMetricRequest` element.
 | |
|     pub async fn get_auth_event_metrics(
 | |
|         state: web::Data<AppState>,
 | |
|         req: actix_web::HttpRequest,
 | |
|         json_payload: web::Json<[GetAuthEventMetricRequest; 1]>,
 | |
|     ) -> impl Responder {
 | |
|         // safety: This shouldn't panic owing to the data type
 | |
|         #[allow(clippy::expect_used)]
 | |
|         let payload = json_payload
 | |
|             .into_inner()
 | |
|             .to_vec()
 | |
|             .pop()
 | |
|             .expect("Couldn't get GetAuthEventMetricRequest");
 | |
|         let flow = AnalyticsFlow::GetAuthMetrics;
 | |
|         Box::pin(api::server_wrap(
 | |
|             flow,
 | |
|             state,
 | |
|             &req,
 | |
|             payload,
 | |
|             |state, auth: AuthenticationData, req, _| async move {
 | |
|                 analytics::auth_events::get_metrics(
 | |
|                     &state.pool,
 | |
|                     auth.merchant_account.get_id(),
 | |
|                     &auth.merchant_account.publishable_key,
 | |
|                     req,
 | |
|                 )
 | |
|                 .await
 | |
|                 .map(ApplicationResponse::Json)
 | |
|             },
 | |
|             &auth::JWTAuth {
 | |
|                 permission: Permission::Analytics,
 | |
|                 minimum_entity_level: EntityType::Merchant,
 | |
|             },
 | |
|             api_locking::LockAction::NotApplicable,
 | |
|         ))
 | |
|         .await
 | |
|     }
 | |
| 
 | |
|     pub async fn get_merchant_payment_filters(
 | |
|         state: web::Data<AppState>,
 | |
|         req: actix_web::HttpRequest,
 | |
|         json_payload: web::Json<GetPaymentFiltersRequest>,
 | |
|     ) -> impl Responder {
 | |
|         let flow = AnalyticsFlow::GetPaymentFilters;
 | |
|         Box::pin(api::server_wrap(
 | |
|             flow,
 | |
|             state,
 | |
|             &req,
 | |
|             json_payload.into_inner(),
 | |
|             |state, auth: AuthenticationData, req, _| async move {
 | |
|                 let org_id = auth.merchant_account.get_org_id();
 | |
|                 let merchant_id = auth.merchant_account.get_id();
 | |
|                 let auth: AuthInfo = AuthInfo::MerchantLevel {
 | |
|                     org_id: org_id.clone(),
 | |
|                     merchant_ids: vec![merchant_id.clone()],
 | |
|                 };
 | |
|                 analytics::payments::get_filters(&state.pool, req, &auth)
 | |
|                     .await
 | |
|                     .map(ApplicationResponse::Json)
 | |
|             },
 | |
|             &auth::JWTAuth {
 | |
|                 permission: Permission::Analytics,
 | |
|                 minimum_entity_level: EntityType::Merchant,
 | |
|             },
 | |
|             api_locking::LockAction::NotApplicable,
 | |
|         ))
 | |
|         .await
 | |
|     }
 | |
| 
 | |
|     pub async fn get_org_payment_filters(
 | |
|         state: web::Data<AppState>,
 | |
|         req: actix_web::HttpRequest,
 | |
|         json_payload: web::Json<GetPaymentFiltersRequest>,
 | |
|     ) -> impl Responder {
 | |
|         let flow = AnalyticsFlow::GetPaymentFilters;
 | |
|         Box::pin(api::server_wrap(
 | |
|             flow,
 | |
|             state,
 | |
|             &req,
 | |
|             json_payload.into_inner(),
 | |
|             |state, auth: AuthenticationData, req, _| async move {
 | |
|                 let org_id = auth.merchant_account.get_org_id();
 | |
|                 let auth: AuthInfo = AuthInfo::OrgLevel {
 | |
|                     org_id: org_id.clone(),
 | |
|                 };
 | |
|                 analytics::payments::get_filters(&state.pool, req, &auth)
 | |
|                     .await
 | |
|                     .map(ApplicationResponse::Json)
 | |
|             },
 | |
|             &auth::JWTAuth {
 | |
|                 permission: Permission::Analytics,
 | |
|                 minimum_entity_level: EntityType::Organization,
 | |
|             },
 | |
|             api_locking::LockAction::NotApplicable,
 | |
|         ))
 | |
|         .await
 | |
|     }
 | |
| 
 | |
|     pub async fn get_profile_payment_filters(
 | |
|         state: web::Data<AppState>,
 | |
|         req: actix_web::HttpRequest,
 | |
|         json_payload: web::Json<GetPaymentFiltersRequest>,
 | |
|     ) -> impl Responder {
 | |
|         let flow = AnalyticsFlow::GetPaymentFilters;
 | |
|         Box::pin(api::server_wrap(
 | |
|             flow,
 | |
|             state,
 | |
|             &req,
 | |
|             json_payload.into_inner(),
 | |
|             |state, auth: AuthenticationData, req, _| async move {
 | |
|                 let org_id = auth.merchant_account.get_org_id();
 | |
|                 let merchant_id = auth.merchant_account.get_id();
 | |
|                 let profile_id = auth
 | |
|                     .profile_id
 | |
|                     .ok_or(report!(UserErrors::JwtProfileIdMissing))
 | |
|                     .change_context(AnalyticsError::AccessForbiddenError)?;
 | |
|                 let auth: AuthInfo = AuthInfo::ProfileLevel {
 | |
|                     org_id: org_id.clone(),
 | |
|                     merchant_id: merchant_id.clone(),
 | |
|                     profile_ids: vec![profile_id.clone()],
 | |
|                 };
 | |
|                 analytics::payments::get_filters(&state.pool, req, &auth)
 | |
|                     .await
 | |
|                     .map(ApplicationResponse::Json)
 | |
|             },
 | |
|             &auth::JWTAuth {
 | |
|                 permission: Permission::Analytics,
 | |
|                 minimum_entity_level: EntityType::Profile,
 | |
|             },
 | |
|             api_locking::LockAction::NotApplicable,
 | |
|         ))
 | |
|         .await
 | |
|     }
 | |
| 
 | |
|     pub async fn get_payment_intents_filters(
 | |
|         state: web::Data<AppState>,
 | |
|         req: actix_web::HttpRequest,
 | |
|         json_payload: web::Json<GetPaymentIntentFiltersRequest>,
 | |
|     ) -> impl Responder {
 | |
|         let flow = AnalyticsFlow::GetPaymentIntentFilters;
 | |
|         Box::pin(api::server_wrap(
 | |
|             flow,
 | |
|             state,
 | |
|             &req,
 | |
|             json_payload.into_inner(),
 | |
|             |state, auth: AuthenticationData, req, _| async move {
 | |
|                 analytics::payment_intents::get_filters(
 | |
|                     &state.pool,
 | |
|                     req,
 | |
|                     auth.merchant_account.get_id(),
 | |
|                 )
 | |
|                 .await
 | |
|                 .map(ApplicationResponse::Json)
 | |
|             },
 | |
|             &auth::JWTAuth {
 | |
|                 permission: Permission::Analytics,
 | |
|                 minimum_entity_level: EntityType::Merchant,
 | |
|             },
 | |
|             api_locking::LockAction::NotApplicable,
 | |
|         ))
 | |
|         .await
 | |
|     }
 | |
| 
 | |
|     pub async fn get_merchant_refund_filters(
 | |
|         state: web::Data<AppState>,
 | |
|         req: actix_web::HttpRequest,
 | |
|         json_payload: web::Json<GetRefundFilterRequest>,
 | |
|     ) -> impl Responder {
 | |
|         let flow = AnalyticsFlow::GetRefundFilters;
 | |
|         Box::pin(api::server_wrap(
 | |
|             flow,
 | |
|             state,
 | |
|             &req,
 | |
|             json_payload.into_inner(),
 | |
|             |state, auth: AuthenticationData, req: GetRefundFilterRequest, _| async move {
 | |
|                 let org_id = auth.merchant_account.get_org_id();
 | |
|                 let merchant_id = auth.merchant_account.get_id();
 | |
|                 let auth: AuthInfo = AuthInfo::MerchantLevel {
 | |
|                     org_id: org_id.clone(),
 | |
|                     merchant_ids: vec![merchant_id.clone()],
 | |
|                 };
 | |
|                 analytics::refunds::get_filters(&state.pool, req, &auth)
 | |
|                     .await
 | |
|                     .map(ApplicationResponse::Json)
 | |
|             },
 | |
|             &auth::JWTAuth {
 | |
|                 permission: Permission::Analytics,
 | |
|                 minimum_entity_level: EntityType::Merchant,
 | |
|             },
 | |
|             api_locking::LockAction::NotApplicable,
 | |
|         ))
 | |
|         .await
 | |
|     }
 | |
| 
 | |
|     pub async fn get_org_refund_filters(
 | |
|         state: web::Data<AppState>,
 | |
|         req: actix_web::HttpRequest,
 | |
|         json_payload: web::Json<GetRefundFilterRequest>,
 | |
|     ) -> impl Responder {
 | |
|         let flow = AnalyticsFlow::GetRefundFilters;
 | |
|         Box::pin(api::server_wrap(
 | |
|             flow,
 | |
|             state,
 | |
|             &req,
 | |
|             json_payload.into_inner(),
 | |
|             |state, auth: AuthenticationData, req: GetRefundFilterRequest, _| async move {
 | |
|                 let org_id = auth.merchant_account.get_org_id();
 | |
|                 let auth: AuthInfo = AuthInfo::OrgLevel {
 | |
|                     org_id: org_id.clone(),
 | |
|                 };
 | |
|                 analytics::refunds::get_filters(&state.pool, req, &auth)
 | |
|                     .await
 | |
|                     .map(ApplicationResponse::Json)
 | |
|             },
 | |
|             &auth::JWTAuth {
 | |
|                 permission: Permission::Analytics,
 | |
|                 minimum_entity_level: EntityType::Organization,
 | |
|             },
 | |
|             api_locking::LockAction::NotApplicable,
 | |
|         ))
 | |
|         .await
 | |
|     }
 | |
| 
 | |
|     pub async fn get_profile_refund_filters(
 | |
|         state: web::Data<AppState>,
 | |
|         req: actix_web::HttpRequest,
 | |
|         json_payload: web::Json<GetRefundFilterRequest>,
 | |
|     ) -> impl Responder {
 | |
|         let flow = AnalyticsFlow::GetRefundFilters;
 | |
|         Box::pin(api::server_wrap(
 | |
|             flow,
 | |
|             state,
 | |
|             &req,
 | |
|             json_payload.into_inner(),
 | |
|             |state, auth: AuthenticationData, req: GetRefundFilterRequest, _| async move {
 | |
|                 let org_id = auth.merchant_account.get_org_id();
 | |
|                 let merchant_id = auth.merchant_account.get_id();
 | |
|                 let profile_id = auth
 | |
|                     .profile_id
 | |
|                     .ok_or(report!(UserErrors::JwtProfileIdMissing))
 | |
|                     .change_context(AnalyticsError::AccessForbiddenError)?;
 | |
|                 let auth: AuthInfo = AuthInfo::ProfileLevel {
 | |
|                     org_id: org_id.clone(),
 | |
|                     merchant_id: merchant_id.clone(),
 | |
|                     profile_ids: vec![profile_id.clone()],
 | |
|                 };
 | |
|                 analytics::refunds::get_filters(&state.pool, req, &auth)
 | |
|                     .await
 | |
|                     .map(ApplicationResponse::Json)
 | |
|             },
 | |
|             &auth::JWTAuth {
 | |
|                 permission: Permission::Analytics,
 | |
|                 minimum_entity_level: EntityType::Profile,
 | |
|             },
 | |
|             api_locking::LockAction::NotApplicable,
 | |
|         ))
 | |
|         .await
 | |
|     }
 | |
| 
 | |
|     pub async fn get_frm_filters(
 | |
|         state: web::Data<AppState>,
 | |
|         req: actix_web::HttpRequest,
 | |
|         json_payload: web::Json<GetFrmFilterRequest>,
 | |
|     ) -> impl Responder {
 | |
|         let flow = AnalyticsFlow::GetFrmFilters;
 | |
|         Box::pin(api::server_wrap(
 | |
|             flow,
 | |
|             state,
 | |
|             &req,
 | |
|             json_payload.into_inner(),
 | |
|             |state, auth: AuthenticationData, req: GetFrmFilterRequest, _| async move {
 | |
|                 analytics::frm::get_filters(&state.pool, req, auth.merchant_account.get_id())
 | |
|                     .await
 | |
|                     .map(ApplicationResponse::Json)
 | |
|             },
 | |
|             &auth::JWTAuth {
 | |
|                 permission: Permission::Analytics,
 | |
|                 minimum_entity_level: EntityType::Merchant,
 | |
|             },
 | |
|             api_locking::LockAction::NotApplicable,
 | |
|         ))
 | |
|         .await
 | |
|     }
 | |
| 
 | |
|     pub async fn get_sdk_event_filters(
 | |
|         state: web::Data<AppState>,
 | |
|         req: actix_web::HttpRequest,
 | |
|         json_payload: web::Json<GetSdkEventFiltersRequest>,
 | |
|     ) -> impl Responder {
 | |
|         let flow = AnalyticsFlow::GetSdkEventFilters;
 | |
|         Box::pin(api::server_wrap(
 | |
|             flow,
 | |
|             state,
 | |
|             &req,
 | |
|             json_payload.into_inner(),
 | |
|             |state, auth: AuthenticationData, req, _| async move {
 | |
|                 analytics::sdk_events::get_filters(
 | |
|                     &state.pool,
 | |
|                     req,
 | |
|                     &auth.merchant_account.publishable_key,
 | |
|                 )
 | |
|                 .await
 | |
|                 .map(ApplicationResponse::Json)
 | |
|             },
 | |
|             &auth::JWTAuth {
 | |
|                 permission: Permission::Analytics,
 | |
|                 minimum_entity_level: EntityType::Merchant,
 | |
|             },
 | |
|             api_locking::LockAction::NotApplicable,
 | |
|         ))
 | |
|         .await
 | |
|     }
 | |
| 
 | |
|     pub async fn get_profile_api_events(
 | |
|         state: web::Data<AppState>,
 | |
|         req: actix_web::HttpRequest,
 | |
|         json_payload: web::Query<api_models::analytics::api_event::ApiLogsRequest>,
 | |
|     ) -> impl Responder {
 | |
|         let flow = AnalyticsFlow::GetApiEvents;
 | |
|         Box::pin(api::server_wrap(
 | |
|             flow,
 | |
|             state,
 | |
|             &req,
 | |
|             json_payload.into_inner(),
 | |
|             |state, auth: AuthenticationData, req, _| async move {
 | |
|                 let payment_id = match req.query_param.clone() {
 | |
|                     QueryType::Payment { payment_id } => payment_id,
 | |
|                     QueryType::Refund { payment_id, .. } => payment_id,
 | |
|                     QueryType::Dispute { payment_id, .. } => payment_id,
 | |
|                 };
 | |
|                 utils::check_if_profile_id_is_present_in_payment_intent(payment_id, &state, &auth)
 | |
|                     .await
 | |
|                     .change_context(AnalyticsError::AccessForbiddenError)?;
 | |
|                 api_events_core(&state.pool, req, auth.merchant_account.get_id())
 | |
|                     .await
 | |
|                     .map(ApplicationResponse::Json)
 | |
|             },
 | |
|             &auth::JWTAuth {
 | |
|                 permission: Permission::Analytics,
 | |
|                 minimum_entity_level: EntityType::Profile,
 | |
|             },
 | |
|             api_locking::LockAction::NotApplicable,
 | |
|         ))
 | |
|         .await
 | |
|     }
 | |
| 
 | |
|     pub async fn get_profile_outgoing_webhook_events(
 | |
|         state: web::Data<AppState>,
 | |
|         req: actix_web::HttpRequest,
 | |
|         json_payload: web::Query<
 | |
|             api_models::analytics::outgoing_webhook_event::OutgoingWebhookLogsRequest,
 | |
|         >,
 | |
|     ) -> impl Responder {
 | |
|         let flow = AnalyticsFlow::GetOutgoingWebhookEvents;
 | |
|         Box::pin(api::server_wrap(
 | |
|             flow,
 | |
|             state,
 | |
|             &req,
 | |
|             json_payload.into_inner(),
 | |
|             |state, auth: AuthenticationData, req, _| async move {
 | |
|                 utils::check_if_profile_id_is_present_in_payment_intent(
 | |
|                     req.payment_id.clone(),
 | |
|                     &state,
 | |
|                     &auth,
 | |
|                 )
 | |
|                 .await
 | |
|                 .change_context(AnalyticsError::AccessForbiddenError)?;
 | |
|                 outgoing_webhook_events_core(&state.pool, req, auth.merchant_account.get_id())
 | |
|                     .await
 | |
|                     .map(ApplicationResponse::Json)
 | |
|             },
 | |
|             &auth::JWTAuth {
 | |
|                 permission: Permission::Analytics,
 | |
|                 minimum_entity_level: EntityType::Profile,
 | |
|             },
 | |
|             api_locking::LockAction::NotApplicable,
 | |
|         ))
 | |
|         .await
 | |
|     }
 | |
| 
 | |
|     pub async fn get_profile_sdk_events(
 | |
|         state: web::Data<AppState>,
 | |
|         req: actix_web::HttpRequest,
 | |
|         json_payload: web::Json<api_models::analytics::sdk_events::SdkEventsRequest>,
 | |
|     ) -> impl Responder {
 | |
|         let flow = AnalyticsFlow::GetSdkEvents;
 | |
|         Box::pin(api::server_wrap(
 | |
|             flow,
 | |
|             state,
 | |
|             &req,
 | |
|             json_payload.into_inner(),
 | |
|             |state, auth: AuthenticationData, req, _| async move {
 | |
|                 utils::check_if_profile_id_is_present_in_payment_intent(
 | |
|                     req.payment_id.clone(),
 | |
|                     &state,
 | |
|                     &auth,
 | |
|                 )
 | |
|                 .await
 | |
|                 .change_context(AnalyticsError::AccessForbiddenError)?;
 | |
|                 sdk_events_core(&state.pool, req, &auth.merchant_account.publishable_key)
 | |
|                     .await
 | |
|                     .map(ApplicationResponse::Json)
 | |
|             },
 | |
|             &auth::JWTAuth {
 | |
|                 permission: Permission::Analytics,
 | |
|                 minimum_entity_level: EntityType::Profile,
 | |
|             },
 | |
|             api_locking::LockAction::NotApplicable,
 | |
|         ))
 | |
|         .await
 | |
|     }
 | |
| 
 | |
|     pub async fn generate_merchant_refund_report(
 | |
|         state: web::Data<AppState>,
 | |
|         req: actix_web::HttpRequest,
 | |
|         json_payload: web::Json<ReportRequest>,
 | |
|     ) -> impl Responder {
 | |
|         let flow = AnalyticsFlow::GenerateRefundReport;
 | |
|         Box::pin(api::server_wrap(
 | |
|             flow,
 | |
|             state.clone(),
 | |
|             &req,
 | |
|             json_payload.into_inner(),
 | |
|             |state, (auth, user_id): auth::AuthenticationDataWithUserId, payload, _| async move {
 | |
|                 let user = UserInterface::find_user_by_id(&*state.global_store, &user_id)
 | |
|                     .await
 | |
|                     .change_context(AnalyticsError::UnknownError)?;
 | |
| 
 | |
|                 let user_email = UserEmail::from_pii_email(user.email)
 | |
|                     .change_context(AnalyticsError::UnknownError)?
 | |
|                     .get_secret();
 | |
| 
 | |
|                 let org_id = auth.merchant_account.get_org_id();
 | |
|                 let merchant_id = auth.merchant_account.get_id();
 | |
|                 let lambda_req = GenerateReportRequest {
 | |
|                     request: payload,
 | |
|                     merchant_id: Some(merchant_id.clone()),
 | |
|                     auth: AuthInfo::MerchantLevel {
 | |
|                         org_id: org_id.clone(),
 | |
|                         merchant_ids: vec![merchant_id.clone()],
 | |
|                     },
 | |
|                     email: user_email,
 | |
|                 };
 | |
| 
 | |
|                 let json_bytes =
 | |
|                     serde_json::to_vec(&lambda_req).map_err(|_| AnalyticsError::UnknownError)?;
 | |
|                 invoke_lambda(
 | |
|                     &state.conf.report_download_config.refund_function,
 | |
|                     &state.conf.report_download_config.region,
 | |
|                     &json_bytes,
 | |
|                 )
 | |
|                 .await
 | |
|                 .map(ApplicationResponse::Json)
 | |
|             },
 | |
|             &auth::JWTAuth {
 | |
|                 permission: Permission::GenerateReport,
 | |
|                 minimum_entity_level: EntityType::Merchant,
 | |
|             },
 | |
|             api_locking::LockAction::NotApplicable,
 | |
|         ))
 | |
|         .await
 | |
|     }
 | |
| 
 | |
|     pub async fn generate_org_refund_report(
 | |
|         state: web::Data<AppState>,
 | |
|         req: actix_web::HttpRequest,
 | |
|         json_payload: web::Json<ReportRequest>,
 | |
|     ) -> impl Responder {
 | |
|         let flow = AnalyticsFlow::GenerateRefundReport;
 | |
|         Box::pin(api::server_wrap(
 | |
|             flow,
 | |
|             state.clone(),
 | |
|             &req,
 | |
|             json_payload.into_inner(),
 | |
|             |state, (auth, user_id): auth::AuthenticationDataWithUserId, payload, _| async move {
 | |
|                 let user = UserInterface::find_user_by_id(&*state.global_store, &user_id)
 | |
|                     .await
 | |
|                     .change_context(AnalyticsError::UnknownError)?;
 | |
| 
 | |
|                 let user_email = UserEmail::from_pii_email(user.email)
 | |
|                     .change_context(AnalyticsError::UnknownError)?
 | |
|                     .get_secret();
 | |
| 
 | |
|                 let org_id = auth.merchant_account.get_org_id();
 | |
|                 let lambda_req = GenerateReportRequest {
 | |
|                     request: payload,
 | |
|                     merchant_id: None,
 | |
|                     auth: AuthInfo::OrgLevel {
 | |
|                         org_id: org_id.clone(),
 | |
|                     },
 | |
|                     email: user_email,
 | |
|                 };
 | |
| 
 | |
|                 let json_bytes =
 | |
|                     serde_json::to_vec(&lambda_req).map_err(|_| AnalyticsError::UnknownError)?;
 | |
|                 invoke_lambda(
 | |
|                     &state.conf.report_download_config.refund_function,
 | |
|                     &state.conf.report_download_config.region,
 | |
|                     &json_bytes,
 | |
|                 )
 | |
|                 .await
 | |
|                 .map(ApplicationResponse::Json)
 | |
|             },
 | |
|             &auth::JWTAuth {
 | |
|                 permission: Permission::GenerateReport,
 | |
|                 minimum_entity_level: EntityType::Organization,
 | |
|             },
 | |
|             api_locking::LockAction::NotApplicable,
 | |
|         ))
 | |
|         .await
 | |
|     }
 | |
| 
 | |
|     pub async fn generate_profile_refund_report(
 | |
|         state: web::Data<AppState>,
 | |
|         req: actix_web::HttpRequest,
 | |
|         json_payload: web::Json<ReportRequest>,
 | |
|     ) -> impl Responder {
 | |
|         let flow = AnalyticsFlow::GenerateRefundReport;
 | |
|         Box::pin(api::server_wrap(
 | |
|             flow,
 | |
|             state.clone(),
 | |
|             &req,
 | |
|             json_payload.into_inner(),
 | |
|             |state, (auth, user_id): auth::AuthenticationDataWithUserId, payload, _| async move {
 | |
|                 let user = UserInterface::find_user_by_id(&*state.global_store, &user_id)
 | |
|                     .await
 | |
|                     .change_context(AnalyticsError::UnknownError)?;
 | |
| 
 | |
|                 let user_email = UserEmail::from_pii_email(user.email)
 | |
|                     .change_context(AnalyticsError::UnknownError)?
 | |
|                     .get_secret();
 | |
| 
 | |
|                 let org_id = auth.merchant_account.get_org_id();
 | |
|                 let merchant_id = auth.merchant_account.get_id();
 | |
|                 let profile_id = auth
 | |
|                     .profile_id
 | |
|                     .ok_or(report!(UserErrors::JwtProfileIdMissing))
 | |
|                     .change_context(AnalyticsError::AccessForbiddenError)?;
 | |
|                 let lambda_req = GenerateReportRequest {
 | |
|                     request: payload,
 | |
|                     merchant_id: Some(merchant_id.clone()),
 | |
|                     auth: AuthInfo::ProfileLevel {
 | |
|                         org_id: org_id.clone(),
 | |
|                         merchant_id: merchant_id.clone(),
 | |
|                         profile_ids: vec![profile_id.clone()],
 | |
|                     },
 | |
|                     email: user_email,
 | |
|                 };
 | |
| 
 | |
|                 let json_bytes =
 | |
|                     serde_json::to_vec(&lambda_req).map_err(|_| AnalyticsError::UnknownError)?;
 | |
|                 invoke_lambda(
 | |
|                     &state.conf.report_download_config.refund_function,
 | |
|                     &state.conf.report_download_config.region,
 | |
|                     &json_bytes,
 | |
|                 )
 | |
|                 .await
 | |
|                 .map(ApplicationResponse::Json)
 | |
|             },
 | |
|             &auth::JWTAuth {
 | |
|                 permission: Permission::GenerateReport,
 | |
|                 minimum_entity_level: EntityType::Profile,
 | |
|             },
 | |
|             api_locking::LockAction::NotApplicable,
 | |
|         ))
 | |
|         .await
 | |
|     }
 | |
| 
 | |
|     pub async fn generate_merchant_dispute_report(
 | |
|         state: web::Data<AppState>,
 | |
|         req: actix_web::HttpRequest,
 | |
|         json_payload: web::Json<ReportRequest>,
 | |
|     ) -> impl Responder {
 | |
|         let flow = AnalyticsFlow::GenerateDisputeReport;
 | |
|         Box::pin(api::server_wrap(
 | |
|             flow,
 | |
|             state.clone(),
 | |
|             &req,
 | |
|             json_payload.into_inner(),
 | |
|             |state, (auth, user_id): auth::AuthenticationDataWithUserId, payload, _| async move {
 | |
|                 let user = UserInterface::find_user_by_id(&*state.global_store, &user_id)
 | |
|                     .await
 | |
|                     .change_context(AnalyticsError::UnknownError)?;
 | |
| 
 | |
|                 let user_email = UserEmail::from_pii_email(user.email)
 | |
|                     .change_context(AnalyticsError::UnknownError)?
 | |
|                     .get_secret();
 | |
| 
 | |
|                 let org_id = auth.merchant_account.get_org_id();
 | |
|                 let merchant_id = auth.merchant_account.get_id();
 | |
|                 let lambda_req = GenerateReportRequest {
 | |
|                     request: payload,
 | |
|                     merchant_id: Some(merchant_id.clone()),
 | |
|                     auth: AuthInfo::MerchantLevel {
 | |
|                         org_id: org_id.clone(),
 | |
|                         merchant_ids: vec![merchant_id.clone()],
 | |
|                     },
 | |
|                     email: user_email,
 | |
|                 };
 | |
| 
 | |
|                 let json_bytes =
 | |
|                     serde_json::to_vec(&lambda_req).map_err(|_| AnalyticsError::UnknownError)?;
 | |
|                 invoke_lambda(
 | |
|                     &state.conf.report_download_config.dispute_function,
 | |
|                     &state.conf.report_download_config.region,
 | |
|                     &json_bytes,
 | |
|                 )
 | |
|                 .await
 | |
|                 .map(ApplicationResponse::Json)
 | |
|             },
 | |
|             &auth::JWTAuth {
 | |
|                 permission: Permission::GenerateReport,
 | |
|                 minimum_entity_level: EntityType::Merchant,
 | |
|             },
 | |
|             api_locking::LockAction::NotApplicable,
 | |
|         ))
 | |
|         .await
 | |
|     }
 | |
| 
 | |
|     pub async fn generate_org_dispute_report(
 | |
|         state: web::Data<AppState>,
 | |
|         req: actix_web::HttpRequest,
 | |
|         json_payload: web::Json<ReportRequest>,
 | |
|     ) -> impl Responder {
 | |
|         let flow = AnalyticsFlow::GenerateDisputeReport;
 | |
|         Box::pin(api::server_wrap(
 | |
|             flow,
 | |
|             state.clone(),
 | |
|             &req,
 | |
|             json_payload.into_inner(),
 | |
|             |state, (auth, user_id): auth::AuthenticationDataWithUserId, payload, _| async move {
 | |
|                 let user = UserInterface::find_user_by_id(&*state.global_store, &user_id)
 | |
|                     .await
 | |
|                     .change_context(AnalyticsError::UnknownError)?;
 | |
| 
 | |
|                 let user_email = UserEmail::from_pii_email(user.email)
 | |
|                     .change_context(AnalyticsError::UnknownError)?
 | |
|                     .get_secret();
 | |
| 
 | |
|                 let org_id = auth.merchant_account.get_org_id();
 | |
|                 let lambda_req = GenerateReportRequest {
 | |
|                     request: payload,
 | |
|                     merchant_id: None,
 | |
|                     auth: AuthInfo::OrgLevel {
 | |
|                         org_id: org_id.clone(),
 | |
|                     },
 | |
|                     email: user_email,
 | |
|                 };
 | |
| 
 | |
|                 let json_bytes =
 | |
|                     serde_json::to_vec(&lambda_req).map_err(|_| AnalyticsError::UnknownError)?;
 | |
|                 invoke_lambda(
 | |
|                     &state.conf.report_download_config.dispute_function,
 | |
|                     &state.conf.report_download_config.region,
 | |
|                     &json_bytes,
 | |
|                 )
 | |
|                 .await
 | |
|                 .map(ApplicationResponse::Json)
 | |
|             },
 | |
|             &auth::JWTAuth {
 | |
|                 permission: Permission::GenerateReport,
 | |
|                 minimum_entity_level: EntityType::Organization,
 | |
|             },
 | |
|             api_locking::LockAction::NotApplicable,
 | |
|         ))
 | |
|         .await
 | |
|     }
 | |
| 
 | |
|     pub async fn generate_profile_dispute_report(
 | |
|         state: web::Data<AppState>,
 | |
|         req: actix_web::HttpRequest,
 | |
|         json_payload: web::Json<ReportRequest>,
 | |
|     ) -> impl Responder {
 | |
|         let flow = AnalyticsFlow::GenerateDisputeReport;
 | |
|         Box::pin(api::server_wrap(
 | |
|             flow,
 | |
|             state.clone(),
 | |
|             &req,
 | |
|             json_payload.into_inner(),
 | |
|             |state, (auth, user_id): auth::AuthenticationDataWithUserId, payload, _| async move {
 | |
|                 let user = UserInterface::find_user_by_id(&*state.global_store, &user_id)
 | |
|                     .await
 | |
|                     .change_context(AnalyticsError::UnknownError)?;
 | |
| 
 | |
|                 let user_email = UserEmail::from_pii_email(user.email)
 | |
|                     .change_context(AnalyticsError::UnknownError)?
 | |
|                     .get_secret();
 | |
| 
 | |
|                 let org_id = auth.merchant_account.get_org_id();
 | |
|                 let merchant_id = auth.merchant_account.get_id();
 | |
|                 let profile_id = auth
 | |
|                     .profile_id
 | |
|                     .ok_or(report!(UserErrors::JwtProfileIdMissing))
 | |
|                     .change_context(AnalyticsError::AccessForbiddenError)?;
 | |
|                 let lambda_req = GenerateReportRequest {
 | |
|                     request: payload,
 | |
|                     merchant_id: Some(merchant_id.clone()),
 | |
|                     auth: AuthInfo::ProfileLevel {
 | |
|                         org_id: org_id.clone(),
 | |
|                         merchant_id: merchant_id.clone(),
 | |
|                         profile_ids: vec![profile_id.clone()],
 | |
|                     },
 | |
|                     email: user_email,
 | |
|                 };
 | |
| 
 | |
|                 let json_bytes =
 | |
|                     serde_json::to_vec(&lambda_req).map_err(|_| AnalyticsError::UnknownError)?;
 | |
|                 invoke_lambda(
 | |
|                     &state.conf.report_download_config.dispute_function,
 | |
|                     &state.conf.report_download_config.region,
 | |
|                     &json_bytes,
 | |
|                 )
 | |
|                 .await
 | |
|                 .map(ApplicationResponse::Json)
 | |
|             },
 | |
|             &auth::JWTAuth {
 | |
|                 permission: Permission::GenerateReport,
 | |
|                 minimum_entity_level: EntityType::Profile,
 | |
|             },
 | |
|             api_locking::LockAction::NotApplicable,
 | |
|         ))
 | |
|         .await
 | |
|     }
 | |
| 
 | |
|     pub async fn generate_merchant_payment_report(
 | |
|         state: web::Data<AppState>,
 | |
|         req: actix_web::HttpRequest,
 | |
|         json_payload: web::Json<ReportRequest>,
 | |
|     ) -> impl Responder {
 | |
|         let flow = AnalyticsFlow::GeneratePaymentReport;
 | |
|         Box::pin(api::server_wrap(
 | |
|             flow,
 | |
|             state.clone(),
 | |
|             &req,
 | |
|             json_payload.into_inner(),
 | |
|             |state, (auth, user_id): auth::AuthenticationDataWithUserId, payload, _| async move {
 | |
|                 let user = UserInterface::find_user_by_id(&*state.global_store, &user_id)
 | |
|                     .await
 | |
|                     .change_context(AnalyticsError::UnknownError)?;
 | |
| 
 | |
|                 let user_email = UserEmail::from_pii_email(user.email)
 | |
|                     .change_context(AnalyticsError::UnknownError)?
 | |
|                     .get_secret();
 | |
| 
 | |
|                 let org_id = auth.merchant_account.get_org_id();
 | |
|                 let merchant_id = auth.merchant_account.get_id();
 | |
|                 let lambda_req = GenerateReportRequest {
 | |
|                     request: payload,
 | |
|                     merchant_id: Some(merchant_id.clone()),
 | |
|                     auth: AuthInfo::MerchantLevel {
 | |
|                         org_id: org_id.clone(),
 | |
|                         merchant_ids: vec![merchant_id.clone()],
 | |
|                     },
 | |
|                     email: user_email,
 | |
|                 };
 | |
| 
 | |
|                 let json_bytes =
 | |
|                     serde_json::to_vec(&lambda_req).map_err(|_| AnalyticsError::UnknownError)?;
 | |
|                 invoke_lambda(
 | |
|                     &state.conf.report_download_config.payment_function,
 | |
|                     &state.conf.report_download_config.region,
 | |
|                     &json_bytes,
 | |
|                 )
 | |
|                 .await
 | |
|                 .map(ApplicationResponse::Json)
 | |
|             },
 | |
|             &auth::JWTAuth {
 | |
|                 permission: Permission::GenerateReport,
 | |
|                 minimum_entity_level: EntityType::Merchant,
 | |
|             },
 | |
|             api_locking::LockAction::NotApplicable,
 | |
|         ))
 | |
|         .await
 | |
|     }
 | |
| 
 | |
|     pub async fn generate_org_payment_report(
 | |
|         state: web::Data<AppState>,
 | |
|         req: actix_web::HttpRequest,
 | |
|         json_payload: web::Json<ReportRequest>,
 | |
|     ) -> impl Responder {
 | |
|         let flow = AnalyticsFlow::GeneratePaymentReport;
 | |
|         Box::pin(api::server_wrap(
 | |
|             flow,
 | |
|             state.clone(),
 | |
|             &req,
 | |
|             json_payload.into_inner(),
 | |
|             |state, (auth, user_id): auth::AuthenticationDataWithUserId, payload, _| async move {
 | |
|                 let user = UserInterface::find_user_by_id(&*state.global_store, &user_id)
 | |
|                     .await
 | |
|                     .change_context(AnalyticsError::UnknownError)?;
 | |
| 
 | |
|                 let user_email = UserEmail::from_pii_email(user.email)
 | |
|                     .change_context(AnalyticsError::UnknownError)?
 | |
|                     .get_secret();
 | |
| 
 | |
|                 let org_id = auth.merchant_account.get_org_id();
 | |
|                 let lambda_req = GenerateReportRequest {
 | |
|                     request: payload,
 | |
|                     merchant_id: None,
 | |
|                     auth: AuthInfo::OrgLevel {
 | |
|                         org_id: org_id.clone(),
 | |
|                     },
 | |
|                     email: user_email,
 | |
|                 };
 | |
| 
 | |
|                 let json_bytes =
 | |
|                     serde_json::to_vec(&lambda_req).map_err(|_| AnalyticsError::UnknownError)?;
 | |
|                 invoke_lambda(
 | |
|                     &state.conf.report_download_config.payment_function,
 | |
|                     &state.conf.report_download_config.region,
 | |
|                     &json_bytes,
 | |
|                 )
 | |
|                 .await
 | |
|                 .map(ApplicationResponse::Json)
 | |
|             },
 | |
|             &auth::JWTAuth {
 | |
|                 permission: Permission::GenerateReport,
 | |
|                 minimum_entity_level: EntityType::Organization,
 | |
|             },
 | |
|             api_locking::LockAction::NotApplicable,
 | |
|         ))
 | |
|         .await
 | |
|     }
 | |
| 
 | |
|     pub async fn generate_profile_payment_report(
 | |
|         state: web::Data<AppState>,
 | |
|         req: actix_web::HttpRequest,
 | |
|         json_payload: web::Json<ReportRequest>,
 | |
|     ) -> impl Responder {
 | |
|         let flow = AnalyticsFlow::GeneratePaymentReport;
 | |
|         Box::pin(api::server_wrap(
 | |
|             flow,
 | |
|             state.clone(),
 | |
|             &req,
 | |
|             json_payload.into_inner(),
 | |
|             |state, (auth, user_id): auth::AuthenticationDataWithUserId, payload, _| async move {
 | |
|                 let user = UserInterface::find_user_by_id(&*state.global_store, &user_id)
 | |
|                     .await
 | |
|                     .change_context(AnalyticsError::UnknownError)?;
 | |
| 
 | |
|                 let user_email = UserEmail::from_pii_email(user.email)
 | |
|                     .change_context(AnalyticsError::UnknownError)?
 | |
|                     .get_secret();
 | |
|                 let org_id = auth.merchant_account.get_org_id();
 | |
|                 let merchant_id = auth.merchant_account.get_id();
 | |
|                 let profile_id = auth
 | |
|                     .profile_id
 | |
|                     .ok_or(report!(UserErrors::JwtProfileIdMissing))
 | |
|                     .change_context(AnalyticsError::AccessForbiddenError)?;
 | |
|                 let lambda_req = GenerateReportRequest {
 | |
|                     request: payload,
 | |
|                     merchant_id: Some(merchant_id.clone()),
 | |
|                     auth: AuthInfo::ProfileLevel {
 | |
|                         org_id: org_id.clone(),
 | |
|                         merchant_id: merchant_id.clone(),
 | |
|                         profile_ids: vec![profile_id.clone()],
 | |
|                     },
 | |
|                     email: user_email,
 | |
|                 };
 | |
| 
 | |
|                 let json_bytes =
 | |
|                     serde_json::to_vec(&lambda_req).map_err(|_| AnalyticsError::UnknownError)?;
 | |
|                 invoke_lambda(
 | |
|                     &state.conf.report_download_config.payment_function,
 | |
|                     &state.conf.report_download_config.region,
 | |
|                     &json_bytes,
 | |
|                 )
 | |
|                 .await
 | |
|                 .map(ApplicationResponse::Json)
 | |
|             },
 | |
|             &auth::JWTAuth {
 | |
|                 permission: Permission::GenerateReport,
 | |
|                 minimum_entity_level: EntityType::Profile,
 | |
|             },
 | |
|             api_locking::LockAction::NotApplicable,
 | |
|         ))
 | |
|         .await
 | |
|     }
 | |
| 
 | |
|     /// # Panics
 | |
|     ///
 | |
|     /// Panics if `json_payload` array does not contain one `GetApiEventMetricRequest` element.
 | |
|     pub async fn get_merchant_api_events_metrics(
 | |
|         state: web::Data<AppState>,
 | |
|         req: actix_web::HttpRequest,
 | |
|         json_payload: web::Json<[GetApiEventMetricRequest; 1]>,
 | |
|     ) -> impl Responder {
 | |
|         // safety: This shouldn't panic owing to the data type
 | |
|         #[allow(clippy::expect_used)]
 | |
|         let payload = json_payload
 | |
|             .into_inner()
 | |
|             .to_vec()
 | |
|             .pop()
 | |
|             .expect("Couldn't get GetApiEventMetricRequest");
 | |
|         let flow = AnalyticsFlow::GetApiEventMetrics;
 | |
|         Box::pin(api::server_wrap(
 | |
|             flow,
 | |
|             state.clone(),
 | |
|             &req,
 | |
|             payload,
 | |
|             |state, auth: AuthenticationData, req, _| async move {
 | |
|                 analytics::api_event::get_api_event_metrics(
 | |
|                     &state.pool,
 | |
|                     auth.merchant_account.get_id(),
 | |
|                     req,
 | |
|                 )
 | |
|                 .await
 | |
|                 .map(ApplicationResponse::Json)
 | |
|             },
 | |
|             &auth::JWTAuth {
 | |
|                 permission: Permission::Analytics,
 | |
|                 minimum_entity_level: EntityType::Merchant,
 | |
|             },
 | |
|             api_locking::LockAction::NotApplicable,
 | |
|         ))
 | |
|         .await
 | |
|     }
 | |
| 
 | |
|     pub async fn get_merchant_api_event_filters(
 | |
|         state: web::Data<AppState>,
 | |
|         req: actix_web::HttpRequest,
 | |
|         json_payload: web::Json<GetApiEventFiltersRequest>,
 | |
|     ) -> impl Responder {
 | |
|         let flow = AnalyticsFlow::GetApiEventFilters;
 | |
|         Box::pin(api::server_wrap(
 | |
|             flow,
 | |
|             state.clone(),
 | |
|             &req,
 | |
|             json_payload.into_inner(),
 | |
|             |state, auth: AuthenticationData, req, _| async move {
 | |
|                 analytics::api_event::get_filters(&state.pool, req, auth.merchant_account.get_id())
 | |
|                     .await
 | |
|                     .map(ApplicationResponse::Json)
 | |
|             },
 | |
|             &auth::JWTAuth {
 | |
|                 permission: Permission::Analytics,
 | |
|                 minimum_entity_level: EntityType::Profile,
 | |
|             },
 | |
|             api_locking::LockAction::NotApplicable,
 | |
|         ))
 | |
|         .await
 | |
|     }
 | |
| 
 | |
|     pub async fn get_profile_connector_events(
 | |
|         state: web::Data<AppState>,
 | |
|         req: actix_web::HttpRequest,
 | |
|         json_payload: web::Query<api_models::analytics::connector_events::ConnectorEventsRequest>,
 | |
|     ) -> impl Responder {
 | |
|         let flow = AnalyticsFlow::GetConnectorEvents;
 | |
|         Box::pin(api::server_wrap(
 | |
|             flow,
 | |
|             state,
 | |
|             &req,
 | |
|             json_payload.into_inner(),
 | |
|             |state, auth: AuthenticationData, req, _| async move {
 | |
|                 utils::check_if_profile_id_is_present_in_payment_intent(
 | |
|                     req.payment_id.clone(),
 | |
|                     &state,
 | |
|                     &auth,
 | |
|                 )
 | |
|                 .await
 | |
|                 .change_context(AnalyticsError::AccessForbiddenError)?;
 | |
|                 connector_events_core(&state.pool, req, auth.merchant_account.get_id())
 | |
|                     .await
 | |
|                     .map(ApplicationResponse::Json)
 | |
|             },
 | |
|             &auth::JWTAuth {
 | |
|                 permission: Permission::Analytics,
 | |
|                 minimum_entity_level: EntityType::Profile,
 | |
|             },
 | |
|             api_locking::LockAction::NotApplicable,
 | |
|         ))
 | |
|         .await
 | |
|     }
 | |
| 
 | |
|     pub async fn get_global_search_results(
 | |
|         state: web::Data<AppState>,
 | |
|         req: actix_web::HttpRequest,
 | |
|         json_payload: web::Json<GetGlobalSearchRequest>,
 | |
|     ) -> impl Responder {
 | |
|         let flow = AnalyticsFlow::GetGlobalSearchResults;
 | |
|         Box::pin(api::server_wrap(
 | |
|             flow,
 | |
|             state.clone(),
 | |
|             &req,
 | |
|             json_payload.into_inner(),
 | |
|             |state, auth: UserFromToken, req, _| async move {
 | |
|                 let role_id = auth.role_id;
 | |
|                 let role_info =
 | |
|                     RoleInfo::from_role_id(&state, &role_id, &auth.merchant_id, &auth.org_id)
 | |
|                         .await
 | |
|                         .change_context(UserErrors::InternalServerError)
 | |
|                         .change_context(OpenSearchError::UnknownError)?;
 | |
|                 let permissions = role_info.get_permissions_set();
 | |
|                 let accessible_indexes: Vec<_> = OPENSEARCH_INDEX_PERMISSIONS
 | |
|                     .iter()
 | |
|                     .filter(|(_, perm)| perm.iter().any(|p| permissions.contains(p)))
 | |
|                     .map(|(i, _)| *i)
 | |
|                     .collect();
 | |
| 
 | |
|                 let merchant_id: MerchantId = auth.merchant_id;
 | |
|                 let org_id: OrganizationId = auth.org_id;
 | |
|                 let search_params: Vec<AuthInfo> = vec![AuthInfo::MerchantLevel {
 | |
|                     org_id: org_id.clone(),
 | |
|                     merchant_ids: vec![merchant_id.clone()],
 | |
|                 }];
 | |
| 
 | |
|                 analytics::search::msearch_results(
 | |
|                     &state.opensearch_client,
 | |
|                     req,
 | |
|                     search_params,
 | |
|                     accessible_indexes,
 | |
|                 )
 | |
|                 .await
 | |
|                 .map(ApplicationResponse::Json)
 | |
|             },
 | |
|             &auth::JWTAuth {
 | |
|                 permission: Permission::Analytics,
 | |
|                 minimum_entity_level: EntityType::Profile,
 | |
|             },
 | |
|             api_locking::LockAction::NotApplicable,
 | |
|         ))
 | |
|         .await
 | |
|     }
 | |
| 
 | |
|     pub async fn get_search_results(
 | |
|         state: web::Data<AppState>,
 | |
|         req: actix_web::HttpRequest,
 | |
|         json_payload: web::Json<GetSearchRequest>,
 | |
|         index: web::Path<SearchIndex>,
 | |
|     ) -> impl Responder {
 | |
|         let index = index.into_inner();
 | |
|         let flow = AnalyticsFlow::GetSearchResults;
 | |
|         let indexed_req = GetSearchRequestWithIndex {
 | |
|             search_req: json_payload.into_inner(),
 | |
|             index,
 | |
|         };
 | |
|         Box::pin(api::server_wrap(
 | |
|             flow,
 | |
|             state.clone(),
 | |
|             &req,
 | |
|             indexed_req,
 | |
|             |state, auth: UserFromToken, req, _| async move {
 | |
|                 let role_id = auth.role_id;
 | |
|                 let role_info =
 | |
|                     RoleInfo::from_role_id(&state, &role_id, &auth.merchant_id, &auth.org_id)
 | |
|                         .await
 | |
|                         .change_context(UserErrors::InternalServerError)
 | |
|                         .change_context(OpenSearchError::UnknownError)?;
 | |
|                 let permissions = role_info.get_permissions_set();
 | |
|                 let _ = OPENSEARCH_INDEX_PERMISSIONS
 | |
|                     .iter()
 | |
|                     .filter(|(ind, _)| *ind == index)
 | |
|                     .find(|i| i.1.iter().any(|p| permissions.contains(p)))
 | |
|                     .ok_or(OpenSearchError::IndexAccessNotPermittedError(index))?;
 | |
| 
 | |
|                 let merchant_id: MerchantId = auth.merchant_id;
 | |
|                 let org_id: OrganizationId = auth.org_id;
 | |
|                 let search_params: Vec<AuthInfo> = vec![AuthInfo::MerchantLevel {
 | |
|                     org_id: org_id.clone(),
 | |
|                     merchant_ids: vec![merchant_id.clone()],
 | |
|                 }];
 | |
| 
 | |
|                 analytics::search::search_results(&state.opensearch_client, req, search_params)
 | |
|                     .await
 | |
|                     .map(ApplicationResponse::Json)
 | |
|             },
 | |
|             &auth::JWTAuth {
 | |
|                 permission: Permission::Analytics,
 | |
|                 minimum_entity_level: EntityType::Profile,
 | |
|             },
 | |
|             api_locking::LockAction::NotApplicable,
 | |
|         ))
 | |
|         .await
 | |
|     }
 | |
| 
 | |
|     pub async fn get_merchant_dispute_filters(
 | |
|         state: web::Data<AppState>,
 | |
|         req: actix_web::HttpRequest,
 | |
|         json_payload: web::Json<api_models::analytics::GetDisputeFilterRequest>,
 | |
|     ) -> impl Responder {
 | |
|         let flow = AnalyticsFlow::GetDisputeFilters;
 | |
|         Box::pin(api::server_wrap(
 | |
|             flow,
 | |
|             state,
 | |
|             &req,
 | |
|             json_payload.into_inner(),
 | |
|             |state, auth: AuthenticationData, req, _| async move {
 | |
|                 let org_id = auth.merchant_account.get_org_id();
 | |
|                 let merchant_id = auth.merchant_account.get_id();
 | |
|                 let auth: AuthInfo = AuthInfo::MerchantLevel {
 | |
|                     org_id: org_id.clone(),
 | |
|                     merchant_ids: vec![merchant_id.clone()],
 | |
|                 };
 | |
|                 analytics::disputes::get_filters(&state.pool, req, &auth)
 | |
|                     .await
 | |
|                     .map(ApplicationResponse::Json)
 | |
|             },
 | |
|             &auth::JWTAuth {
 | |
|                 permission: Permission::Analytics,
 | |
|                 minimum_entity_level: EntityType::Merchant,
 | |
|             },
 | |
|             api_locking::LockAction::NotApplicable,
 | |
|         ))
 | |
|         .await
 | |
|     }
 | |
| 
 | |
|     pub async fn get_profile_dispute_filters(
 | |
|         state: web::Data<AppState>,
 | |
|         req: actix_web::HttpRequest,
 | |
|         json_payload: web::Json<api_models::analytics::GetDisputeFilterRequest>,
 | |
|     ) -> impl Responder {
 | |
|         let flow = AnalyticsFlow::GetDisputeFilters;
 | |
|         Box::pin(api::server_wrap(
 | |
|             flow,
 | |
|             state,
 | |
|             &req,
 | |
|             json_payload.into_inner(),
 | |
|             |state, auth: AuthenticationData, req, _| async move {
 | |
|                 let org_id = auth.merchant_account.get_org_id();
 | |
|                 let merchant_id = auth.merchant_account.get_id();
 | |
|                 let profile_id = auth
 | |
|                     .profile_id
 | |
|                     .ok_or(report!(UserErrors::JwtProfileIdMissing))
 | |
|                     .change_context(AnalyticsError::AccessForbiddenError)?;
 | |
|                 let auth: AuthInfo = AuthInfo::ProfileLevel {
 | |
|                     org_id: org_id.clone(),
 | |
|                     merchant_id: merchant_id.clone(),
 | |
|                     profile_ids: vec![profile_id.clone()],
 | |
|                 };
 | |
|                 analytics::disputes::get_filters(&state.pool, req, &auth)
 | |
|                     .await
 | |
|                     .map(ApplicationResponse::Json)
 | |
|             },
 | |
|             &auth::JWTAuth {
 | |
|                 permission: Permission::Analytics,
 | |
|                 minimum_entity_level: EntityType::Profile,
 | |
|             },
 | |
|             api_locking::LockAction::NotApplicable,
 | |
|         ))
 | |
|         .await
 | |
|     }
 | |
| 
 | |
|     pub async fn get_org_dispute_filters(
 | |
|         state: web::Data<AppState>,
 | |
|         req: actix_web::HttpRequest,
 | |
|         json_payload: web::Json<api_models::analytics::GetDisputeFilterRequest>,
 | |
|     ) -> impl Responder {
 | |
|         let flow = AnalyticsFlow::GetDisputeFilters;
 | |
|         Box::pin(api::server_wrap(
 | |
|             flow,
 | |
|             state,
 | |
|             &req,
 | |
|             json_payload.into_inner(),
 | |
|             |state, auth: AuthenticationData, req, _| async move {
 | |
|                 let org_id = auth.merchant_account.get_org_id();
 | |
|                 let auth: AuthInfo = AuthInfo::OrgLevel {
 | |
|                     org_id: org_id.clone(),
 | |
|                 };
 | |
|                 analytics::disputes::get_filters(&state.pool, req, &auth)
 | |
|                     .await
 | |
|                     .map(ApplicationResponse::Json)
 | |
|             },
 | |
|             &auth::JWTAuth {
 | |
|                 permission: Permission::Analytics,
 | |
|                 minimum_entity_level: EntityType::Organization,
 | |
|             },
 | |
|             api_locking::LockAction::NotApplicable,
 | |
|         ))
 | |
|         .await
 | |
|     }
 | |
| 
 | |
|     /// # Panics
 | |
|     ///
 | |
|     /// Panics if `json_payload` array does not contain one `GetDisputeMetricRequest` element.
 | |
|     pub async fn get_merchant_dispute_metrics(
 | |
|         state: web::Data<AppState>,
 | |
|         req: actix_web::HttpRequest,
 | |
|         json_payload: web::Json<[GetDisputeMetricRequest; 1]>,
 | |
|     ) -> impl Responder {
 | |
|         // safety: This shouldn't panic owing to the data type
 | |
|         #[allow(clippy::expect_used)]
 | |
|         let payload = json_payload
 | |
|             .into_inner()
 | |
|             .to_vec()
 | |
|             .pop()
 | |
|             .expect("Couldn't get GetDisputeMetricRequest");
 | |
|         let flow = AnalyticsFlow::GetDisputeMetrics;
 | |
|         Box::pin(api::server_wrap(
 | |
|             flow,
 | |
|             state,
 | |
|             &req,
 | |
|             payload,
 | |
|             |state, auth: AuthenticationData, req, _| async move {
 | |
|                 let org_id = auth.merchant_account.get_org_id();
 | |
|                 let merchant_id = auth.merchant_account.get_id();
 | |
|                 let auth: AuthInfo = AuthInfo::MerchantLevel {
 | |
|                     org_id: org_id.clone(),
 | |
|                     merchant_ids: vec![merchant_id.clone()],
 | |
|                 };
 | |
|                 analytics::disputes::get_metrics(&state.pool, &auth, req)
 | |
|                     .await
 | |
|                     .map(ApplicationResponse::Json)
 | |
|             },
 | |
|             &auth::JWTAuth {
 | |
|                 permission: Permission::Analytics,
 | |
|                 minimum_entity_level: EntityType::Merchant,
 | |
|             },
 | |
|             api_locking::LockAction::NotApplicable,
 | |
|         ))
 | |
|         .await
 | |
|     }
 | |
| 
 | |
|     /// # Panics
 | |
|     ///
 | |
|     /// Panics if `json_payload` array does not contain one `GetDisputeMetricRequest` element.
 | |
|     pub async fn get_profile_dispute_metrics(
 | |
|         state: web::Data<AppState>,
 | |
|         req: actix_web::HttpRequest,
 | |
|         json_payload: web::Json<[GetDisputeMetricRequest; 1]>,
 | |
|     ) -> impl Responder {
 | |
|         // safety: This shouldn't panic owing to the data type
 | |
|         #[allow(clippy::expect_used)]
 | |
|         let payload = json_payload
 | |
|             .into_inner()
 | |
|             .to_vec()
 | |
|             .pop()
 | |
|             .expect("Couldn't get GetDisputeMetricRequest");
 | |
|         let flow = AnalyticsFlow::GetDisputeMetrics;
 | |
|         Box::pin(api::server_wrap(
 | |
|             flow,
 | |
|             state,
 | |
|             &req,
 | |
|             payload,
 | |
|             |state, auth: AuthenticationData, req, _| async move {
 | |
|                 let org_id = auth.merchant_account.get_org_id();
 | |
|                 let merchant_id = auth.merchant_account.get_id();
 | |
|                 let profile_id = auth
 | |
|                     .profile_id
 | |
|                     .ok_or(report!(UserErrors::JwtProfileIdMissing))
 | |
|                     .change_context(AnalyticsError::AccessForbiddenError)?;
 | |
|                 let auth: AuthInfo = AuthInfo::ProfileLevel {
 | |
|                     org_id: org_id.clone(),
 | |
|                     merchant_id: merchant_id.clone(),
 | |
|                     profile_ids: vec![profile_id.clone()],
 | |
|                 };
 | |
|                 analytics::disputes::get_metrics(&state.pool, &auth, req)
 | |
|                     .await
 | |
|                     .map(ApplicationResponse::Json)
 | |
|             },
 | |
|             &auth::JWTAuth {
 | |
|                 permission: Permission::Analytics,
 | |
|                 minimum_entity_level: EntityType::Profile,
 | |
|             },
 | |
|             api_locking::LockAction::NotApplicable,
 | |
|         ))
 | |
|         .await
 | |
|     }
 | |
| 
 | |
|     /// # Panics
 | |
|     ///
 | |
|     /// Panics if `json_payload` array does not contain one `GetDisputeMetricRequest` element.
 | |
|     pub async fn get_org_dispute_metrics(
 | |
|         state: web::Data<AppState>,
 | |
|         req: actix_web::HttpRequest,
 | |
|         json_payload: web::Json<[GetDisputeMetricRequest; 1]>,
 | |
|     ) -> impl Responder {
 | |
|         // safety: This shouldn't panic owing to the data type
 | |
|         #[allow(clippy::expect_used)]
 | |
|         let payload = json_payload
 | |
|             .into_inner()
 | |
|             .to_vec()
 | |
|             .pop()
 | |
|             .expect("Couldn't get GetDisputeMetricRequest");
 | |
|         let flow = AnalyticsFlow::GetDisputeMetrics;
 | |
|         Box::pin(api::server_wrap(
 | |
|             flow,
 | |
|             state,
 | |
|             &req,
 | |
|             payload,
 | |
|             |state, auth: AuthenticationData, req, _| async move {
 | |
|                 let org_id = auth.merchant_account.get_org_id();
 | |
|                 let auth: AuthInfo = AuthInfo::OrgLevel {
 | |
|                     org_id: org_id.clone(),
 | |
|                 };
 | |
|                 analytics::disputes::get_metrics(&state.pool, &auth, req)
 | |
|                     .await
 | |
|                     .map(ApplicationResponse::Json)
 | |
|             },
 | |
|             &auth::JWTAuth {
 | |
|                 permission: Permission::Analytics,
 | |
|                 minimum_entity_level: EntityType::Organization,
 | |
|             },
 | |
|             api_locking::LockAction::NotApplicable,
 | |
|         ))
 | |
|         .await
 | |
|     }
 | |
| }
 |