refactor: exposed auth analytics at merchant,org and profile levels (#8335)

This commit is contained in:
Sanskar Atrey
2025-07-01 16:51:35 +05:30
committed by GitHub
parent 69ab255394
commit e638f239d3
17 changed files with 368 additions and 200 deletions

View File

@ -27,7 +27,7 @@ use crate::{
#[instrument(skip_all)]
pub async fn get_metrics(
pool: &AnalyticsProvider,
merchant_id: &common_utils::id_type::MerchantId,
auth: &AuthInfo,
req: GetAuthEventMetricRequest,
) -> AnalyticsResult<AuthEventMetricsResponse<MetricsBucketResponse>> {
let mut metrics_accumulator: HashMap<
@ -38,14 +38,14 @@ pub async fn get_metrics(
let mut set = tokio::task::JoinSet::new();
for metric_type in req.metrics.iter().cloned() {
let req = req.clone();
let merchant_id_scoped = merchant_id.to_owned();
let auth_scoped = auth.to_owned();
let pool = pool.clone();
set.spawn(async move {
let data = pool
.get_auth_event_metrics(
&metric_type,
&req.group_by_names.clone(),
&merchant_id_scoped,
&auth_scoped,
&req.filters,
req.time_series.map(|t| t.granularity),
&req.time_range,
@ -130,7 +130,7 @@ pub async fn get_metrics(
pub async fn get_filters(
pool: &AnalyticsProvider,
req: GetAuthEventFilterRequest,
merchant_id: &common_utils::id_type::MerchantId,
auth: &AuthInfo,
) -> AnalyticsResult<AuthEventFiltersResponse> {
let mut res = AuthEventFiltersResponse::default();
for dim in req.group_by_names {
@ -139,14 +139,14 @@ pub async fn get_filters(
Err(report!(AnalyticsError::UnknownError))
}
AnalyticsProvider::Clickhouse(pool) => {
get_auth_events_filter_for_dimension(dim, merchant_id, &req.time_range, pool)
get_auth_events_filter_for_dimension(dim, auth, &req.time_range, pool)
.await
.map_err(|e| e.change_context(AnalyticsError::UnknownError))
}
AnalyticsProvider::CombinedCkh(sqlx_pool, ckh_pool) | AnalyticsProvider::CombinedSqlx(sqlx_pool, ckh_pool) => {
let ckh_result = get_auth_events_filter_for_dimension(
dim,
merchant_id,
auth,
&req.time_range,
ckh_pool,
)
@ -154,7 +154,7 @@ pub async fn get_filters(
.map_err(|e| e.change_context(AnalyticsError::UnknownError));
let sqlx_result = get_auth_events_filter_for_dimension(
dim,
merchant_id,
auth,
&req.time_range,
sqlx_pool,
)

View File

@ -6,6 +6,7 @@ use error_stack::ResultExt;
use time::PrimitiveDateTime;
use crate::{
enums::AuthInfo,
query::{Aggregate, GroupByClause, QueryBuilder, QueryFilter, ToSql, Window},
types::{
AnalyticsCollection, AnalyticsDataSource, DBEnumWrapper, FiltersError, FiltersResult,
@ -17,7 +18,7 @@ pub trait AuthEventFilterAnalytics: LoadRow<AuthEventFilterRow> {}
pub async fn get_auth_events_filter_for_dimension<T>(
dimension: AuthEventDimensions,
merchant_id: &common_utils::id_type::MerchantId,
auth: &AuthInfo,
time_range: &TimeRange,
pool: &T,
) -> FiltersResult<Vec<AuthEventFilterRow>>
@ -38,12 +39,10 @@ where
.attach_printable("Error filtering time range")
.switch()?;
query_builder
.add_filter_clause("merchant_id", merchant_id)
.switch()?;
query_builder.set_distinct();
auth.set_filter_clause(&mut query_builder).switch()?;
query_builder
.execute_query::<AuthEventFilterRow, _>(pool)
.await

View File

@ -12,6 +12,7 @@ use time::PrimitiveDateTime;
use crate::{
query::{Aggregate, GroupByClause, ToSql, Window},
types::{AnalyticsCollection, AnalyticsDataSource, DBEnumWrapper, LoadRow, MetricsResult},
AuthInfo,
};
mod authentication_attempt_count;
@ -86,7 +87,7 @@ where
{
async fn load_metrics(
&self,
merchant_id: &common_utils::id_type::MerchantId,
auth: &AuthInfo,
dimensions: &[AuthEventDimensions],
filters: &AuthEventFilters,
granularity: Option<Granularity>,
@ -107,7 +108,7 @@ where
{
async fn load_metrics(
&self,
merchant_id: &common_utils::id_type::MerchantId,
auth: &AuthInfo,
dimensions: &[AuthEventDimensions],
filters: &AuthEventFilters,
granularity: Option<Granularity>,
@ -117,146 +118,62 @@ where
match self {
Self::AuthenticationCount => {
AuthenticationCount
.load_metrics(
merchant_id,
dimensions,
filters,
granularity,
time_range,
pool,
)
.load_metrics(auth, dimensions, filters, granularity, time_range, pool)
.await
}
Self::AuthenticationAttemptCount => {
AuthenticationAttemptCount
.load_metrics(
merchant_id,
dimensions,
filters,
granularity,
time_range,
pool,
)
.load_metrics(auth, dimensions, filters, granularity, time_range, pool)
.await
}
Self::AuthenticationSuccessCount => {
AuthenticationSuccessCount
.load_metrics(
merchant_id,
dimensions,
filters,
granularity,
time_range,
pool,
)
.load_metrics(auth, dimensions, filters, granularity, time_range, pool)
.await
}
Self::ChallengeFlowCount => {
ChallengeFlowCount
.load_metrics(
merchant_id,
dimensions,
filters,
granularity,
time_range,
pool,
)
.load_metrics(auth, dimensions, filters, granularity, time_range, pool)
.await
}
Self::ChallengeAttemptCount => {
ChallengeAttemptCount
.load_metrics(
merchant_id,
dimensions,
filters,
granularity,
time_range,
pool,
)
.load_metrics(auth, dimensions, filters, granularity, time_range, pool)
.await
}
Self::ChallengeSuccessCount => {
ChallengeSuccessCount
.load_metrics(
merchant_id,
dimensions,
filters,
granularity,
time_range,
pool,
)
.load_metrics(auth, dimensions, filters, granularity, time_range, pool)
.await
}
Self::FrictionlessFlowCount => {
FrictionlessFlowCount
.load_metrics(
merchant_id,
dimensions,
filters,
granularity,
time_range,
pool,
)
.load_metrics(auth, dimensions, filters, granularity, time_range, pool)
.await
}
Self::FrictionlessSuccessCount => {
FrictionlessSuccessCount
.load_metrics(
merchant_id,
dimensions,
filters,
granularity,
time_range,
pool,
)
.load_metrics(auth, dimensions, filters, granularity, time_range, pool)
.await
}
Self::AuthenticationErrorMessage => {
AuthenticationErrorMessage
.load_metrics(
merchant_id,
dimensions,
filters,
granularity,
time_range,
pool,
)
.load_metrics(auth, dimensions, filters, granularity, time_range, pool)
.await
}
Self::AuthenticationFunnel => {
AuthenticationFunnel
.load_metrics(
merchant_id,
dimensions,
filters,
granularity,
time_range,
pool,
)
.load_metrics(auth, dimensions, filters, granularity, time_range, pool)
.await
}
Self::AuthenticationExemptionApprovedCount => {
AuthenticationExemptionApprovedCount
.load_metrics(
merchant_id,
dimensions,
filters,
granularity,
time_range,
pool,
)
.load_metrics(auth, dimensions, filters, granularity, time_range, pool)
.await
}
Self::AuthenticationExemptionRequestedCount => {
AuthenticationExemptionRequestedCount
.load_metrics(
merchant_id,
dimensions,
filters,
granularity,
time_range,
pool,
)
.load_metrics(auth, dimensions, filters, granularity, time_range, pool)
.await
}
}

View File

@ -13,6 +13,7 @@ use super::AuthEventMetricRow;
use crate::{
query::{Aggregate, GroupByClause, QueryBuilder, QueryFilter, SeriesBucket, ToSql, Window},
types::{AnalyticsCollection, AnalyticsDataSource, MetricsError, MetricsResult},
AuthInfo,
};
#[derive(Default)]
@ -30,7 +31,7 @@ where
{
async fn load_metrics(
&self,
merchant_id: &common_utils::id_type::MerchantId,
auth: &AuthInfo,
dimensions: &[AuthEventDimensions],
filters: &AuthEventFilters,
granularity: Option<Granularity>,
@ -65,10 +66,6 @@ where
})
.switch()?;
query_builder
.add_filter_clause("merchant_id", merchant_id)
.switch()?;
query_builder
.add_filter_in_range_clause(
"authentication_status",
@ -80,6 +77,7 @@ where
.set_filter_clause(&mut query_builder)
.attach_printable("Error filtering time range")
.switch()?;
auth.set_filter_clause(&mut query_builder).switch()?;
for dim in dimensions.iter() {
query_builder

View File

@ -12,6 +12,7 @@ use super::AuthEventMetricRow;
use crate::{
query::{Aggregate, GroupByClause, QueryBuilder, QueryFilter, SeriesBucket, ToSql, Window},
types::{AnalyticsCollection, AnalyticsDataSource, MetricsError, MetricsResult},
AuthInfo,
};
#[derive(Default)]
@ -29,7 +30,7 @@ where
{
async fn load_metrics(
&self,
merchant_id: &common_utils::id_type::MerchantId,
auth: &AuthInfo,
dimensions: &[AuthEventDimensions],
filters: &AuthEventFilters,
granularity: Option<Granularity>,
@ -62,14 +63,12 @@ where
})
.switch()?;
query_builder
.add_filter_clause("merchant_id", merchant_id)
.switch()?;
filters.set_filter_clause(&mut query_builder).switch()?;
time_range
.set_filter_clause(&mut query_builder)
.attach_printable("Error filtering time range")
.switch()?;
auth.set_filter_clause(&mut query_builder).switch()?;
for dim in dimensions.iter() {
query_builder

View File

@ -16,6 +16,7 @@ use crate::{
ToSql, Window,
},
types::{AnalyticsCollection, AnalyticsDataSource, MetricsError, MetricsResult},
AuthInfo,
};
#[derive(Default)]
@ -33,7 +34,7 @@ where
{
async fn load_metrics(
&self,
merchant_id: &common_utils::id_type::MerchantId,
auth: &AuthInfo,
dimensions: &[AuthEventDimensions],
filters: &AuthEventFilters,
granularity: Option<Granularity>,
@ -64,10 +65,6 @@ where
})
.switch()?;
query_builder
.add_filter_clause("merchant_id", merchant_id)
.switch()?;
query_builder
.add_filter_clause("authentication_status", AuthenticationStatus::Failed)
.switch()?;
@ -84,6 +81,7 @@ where
.set_filter_clause(&mut query_builder)
.attach_printable("Error filtering time range")
.switch()?;
auth.set_filter_clause(&mut query_builder).switch()?;
for dim in dimensions.iter() {
query_builder

View File

@ -12,6 +12,7 @@ use super::AuthEventMetricRow;
use crate::{
query::{Aggregate, GroupByClause, QueryBuilder, QueryFilter, SeriesBucket, ToSql, Window},
types::{AnalyticsCollection, AnalyticsDataSource, MetricsError, MetricsResult},
AuthInfo,
};
#[derive(Default)]
@ -29,7 +30,7 @@ where
{
async fn load_metrics(
&self,
merchant_id: &common_utils::id_type::MerchantId,
auth: &AuthInfo,
dimensions: &[AuthEventDimensions],
filters: &AuthEventFilters,
granularity: Option<Granularity>,
@ -62,10 +63,6 @@ where
})
.switch()?;
query_builder
.add_filter_clause("merchant_id", merchant_id)
.switch()?;
query_builder
.add_filter_clause(AuthEventDimensions::ExemptionAccepted, true)
.switch()?;
@ -74,6 +71,7 @@ where
.set_filter_clause(&mut query_builder)
.attach_printable("Error filtering time range")
.switch()?;
auth.set_filter_clause(&mut query_builder).switch()?;
for dim in dimensions.iter() {
query_builder

View File

@ -12,6 +12,7 @@ use super::AuthEventMetricRow;
use crate::{
query::{Aggregate, GroupByClause, QueryBuilder, QueryFilter, SeriesBucket, ToSql, Window},
types::{AnalyticsCollection, AnalyticsDataSource, MetricsError, MetricsResult},
AuthInfo,
};
#[derive(Default)]
@ -29,7 +30,7 @@ where
{
async fn load_metrics(
&self,
merchant_id: &common_utils::id_type::MerchantId,
auth: &AuthInfo,
dimensions: &[AuthEventDimensions],
filters: &AuthEventFilters,
granularity: Option<Granularity>,
@ -62,10 +63,6 @@ where
})
.switch()?;
query_builder
.add_filter_clause("merchant_id", merchant_id)
.switch()?;
query_builder
.add_filter_clause(AuthEventDimensions::ExemptionRequested, true)
.switch()?;
@ -75,6 +72,7 @@ where
.set_filter_clause(&mut query_builder)
.attach_printable("Error filtering time range")
.switch()?;
auth.set_filter_clause(&mut query_builder).switch()?;
for dim in dimensions.iter() {
query_builder

View File

@ -15,6 +15,7 @@ use crate::{
Window,
},
types::{AnalyticsCollection, AnalyticsDataSource, MetricsError, MetricsResult},
AuthInfo,
};
#[derive(Default)]
@ -32,7 +33,7 @@ where
{
async fn load_metrics(
&self,
merchant_id: &common_utils::id_type::MerchantId,
auth: &AuthInfo,
dimensions: &[AuthEventDimensions],
filters: &AuthEventFilters,
granularity: Option<Granularity>,
@ -65,10 +66,6 @@ where
})
.switch()?;
query_builder
.add_filter_clause("merchant_id", merchant_id)
.switch()?;
query_builder
.add_custom_filter_clause(
AuthEventDimensions::TransactionStatus,
@ -81,6 +78,7 @@ where
.set_filter_clause(&mut query_builder)
.attach_printable("Error filtering time range")
.switch()?;
auth.set_filter_clause(&mut query_builder).switch()?;
for dim in dimensions.iter() {
query_builder

View File

@ -13,6 +13,7 @@ use super::AuthEventMetricRow;
use crate::{
query::{Aggregate, GroupByClause, QueryBuilder, QueryFilter, SeriesBucket, ToSql, Window},
types::{AnalyticsCollection, AnalyticsDataSource, MetricsError, MetricsResult},
AuthInfo,
};
#[derive(Default)]
@ -30,7 +31,7 @@ where
{
async fn load_metrics(
&self,
merchant_id: &common_utils::id_type::MerchantId,
auth: &AuthInfo,
dimensions: &[AuthEventDimensions],
filters: &AuthEventFilters,
granularity: Option<Granularity>,
@ -63,10 +64,6 @@ where
})
.switch()?;
query_builder
.add_filter_clause("merchant_id", merchant_id)
.switch()?;
query_builder
.add_filter_clause("authentication_status", AuthenticationStatus::Success)
.switch()?;
@ -75,6 +72,7 @@ where
.set_filter_clause(&mut query_builder)
.attach_printable("Error filtering time range")
.switch()?;
auth.set_filter_clause(&mut query_builder).switch()?;
for dim in dimensions.iter() {
query_builder

View File

@ -13,6 +13,7 @@ use super::AuthEventMetricRow;
use crate::{
query::{Aggregate, GroupByClause, QueryBuilder, QueryFilter, SeriesBucket, ToSql, Window},
types::{AnalyticsCollection, AnalyticsDataSource, MetricsError, MetricsResult},
AuthInfo,
};
#[derive(Default)]
@ -30,7 +31,7 @@ where
{
async fn load_metrics(
&self,
merchant_id: &common_utils::id_type::MerchantId,
auth: &AuthInfo,
dimensions: &[AuthEventDimensions],
filters: &AuthEventFilters,
granularity: Option<Granularity>,
@ -63,10 +64,6 @@ where
})
.switch()?;
query_builder
.add_filter_clause("merchant_id", merchant_id)
.switch()?;
query_builder
.add_filter_clause(
"authentication_type",
@ -85,6 +82,7 @@ where
.set_filter_clause(&mut query_builder)
.attach_printable("Error filtering time range")
.switch()?;
auth.set_filter_clause(&mut query_builder).switch()?;
for dim in dimensions.iter() {
query_builder

View File

@ -13,6 +13,7 @@ use super::AuthEventMetricRow;
use crate::{
query::{Aggregate, GroupByClause, QueryBuilder, QueryFilter, SeriesBucket, ToSql, Window},
types::{AnalyticsCollection, AnalyticsDataSource, MetricsError, MetricsResult},
AuthInfo,
};
#[derive(Default)]
@ -30,7 +31,7 @@ where
{
async fn load_metrics(
&self,
merchant_id: &common_utils::id_type::MerchantId,
auth: &AuthInfo,
dimensions: &[AuthEventDimensions],
filters: &AuthEventFilters,
granularity: Option<Granularity>,
@ -63,10 +64,6 @@ where
})
.switch()?;
query_builder
.add_filter_clause("merchant_id", merchant_id)
.switch()?;
query_builder
.add_filter_clause(
"authentication_type",
@ -78,6 +75,7 @@ where
.set_filter_clause(&mut query_builder)
.attach_printable("Error filtering time range")
.switch()?;
auth.set_filter_clause(&mut query_builder).switch()?;
for dim in dimensions.iter() {
query_builder

View File

@ -13,6 +13,7 @@ use super::AuthEventMetricRow;
use crate::{
query::{Aggregate, GroupByClause, QueryBuilder, QueryFilter, SeriesBucket, ToSql, Window},
types::{AnalyticsCollection, AnalyticsDataSource, MetricsError, MetricsResult},
AuthInfo,
};
#[derive(Default)]
@ -30,7 +31,7 @@ where
{
async fn load_metrics(
&self,
merchant_id: &common_utils::id_type::MerchantId,
auth: &AuthInfo,
dimensions: &[AuthEventDimensions],
filters: &AuthEventFilters,
granularity: Option<Granularity>,
@ -63,10 +64,6 @@ where
})
.switch()?;
query_builder
.add_filter_clause("merchant_id", merchant_id)
.switch()?;
query_builder
.add_filter_clause("authentication_status", AuthenticationStatus::Success)
.switch()?;
@ -82,6 +79,7 @@ where
.set_filter_clause(&mut query_builder)
.attach_printable("Error filtering time range")
.switch()?;
auth.set_filter_clause(&mut query_builder).switch()?;
for dim in dimensions.iter() {
query_builder

View File

@ -13,6 +13,7 @@ use super::AuthEventMetricRow;
use crate::{
query::{Aggregate, GroupByClause, QueryBuilder, QueryFilter, SeriesBucket, ToSql, Window},
types::{AnalyticsCollection, AnalyticsDataSource, MetricsError, MetricsResult},
AuthInfo,
};
#[derive(Default)]
@ -30,7 +31,7 @@ where
{
async fn load_metrics(
&self,
merchant_id: &common_utils::id_type::MerchantId,
auth: &AuthInfo,
dimensions: &[AuthEventDimensions],
filters: &AuthEventFilters,
granularity: Option<Granularity>,
@ -63,10 +64,6 @@ where
})
.switch()?;
query_builder
.add_filter_clause("merchant_id", merchant_id)
.switch()?;
query_builder
.add_filter_clause(
"authentication_type",
@ -78,6 +75,7 @@ where
.set_filter_clause(&mut query_builder)
.attach_printable("Error filtering time range")
.switch()?;
auth.set_filter_clause(&mut query_builder).switch()?;
for dim in dimensions.iter() {
query_builder

View File

@ -13,6 +13,7 @@ use super::AuthEventMetricRow;
use crate::{
query::{Aggregate, GroupByClause, QueryBuilder, QueryFilter, SeriesBucket, ToSql, Window},
types::{AnalyticsCollection, AnalyticsDataSource, MetricsError, MetricsResult},
AuthInfo,
};
#[derive(Default)]
@ -30,7 +31,7 @@ where
{
async fn load_metrics(
&self,
merchant_id: &common_utils::id_type::MerchantId,
auth: &AuthInfo,
dimensions: &[AuthEventDimensions],
filters: &AuthEventFilters,
granularity: Option<Granularity>,
@ -63,10 +64,6 @@ where
})
.switch()?;
query_builder
.add_filter_clause("merchant_id", merchant_id)
.switch()?;
query_builder
.add_filter_clause(
"authentication_type",
@ -82,6 +79,7 @@ where
.set_filter_clause(&mut query_builder)
.attach_printable("Error filtering time range")
.switch()?;
auth.set_filter_clause(&mut query_builder).switch()?;
for dim in dimensions.iter() {
query_builder

View File

@ -912,7 +912,7 @@ impl AnalyticsProvider {
&self,
metric: &AuthEventMetrics,
dimensions: &[AuthEventDimensions],
merchant_id: &common_utils::id_type::MerchantId,
auth: &AuthInfo,
filters: &AuthEventFilters,
granularity: Option<Granularity>,
time_range: &TimeRange,
@ -921,20 +921,13 @@ impl AnalyticsProvider {
Self::Sqlx(_pool) => Err(report!(MetricsError::NotImplemented)),
Self::Clickhouse(pool) => {
metric
.load_metrics(
merchant_id,
dimensions,
filters,
granularity,
time_range,
pool,
)
.load_metrics(auth, dimensions, filters, granularity, time_range, pool)
.await
}
Self::CombinedCkh(_sqlx_pool, ckh_pool) | Self::CombinedSqlx(_sqlx_pool, ckh_pool) => {
metric
.load_metrics(
merchant_id,
auth,
dimensions,
filters,
granularity,