mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-30 09:38:33 +08:00
feat: add resources and granular permission groups for reconciliation (#6591)
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
@ -446,3 +446,20 @@ pub enum StripeChargeType {
|
|||||||
pub fn convert_frm_connector(connector_name: &str) -> Option<FrmConnectors> {
|
pub fn convert_frm_connector(connector_name: &str) -> Option<FrmConnectors> {
|
||||||
FrmConnectors::from_str(connector_name).ok()
|
FrmConnectors::from_str(connector_name).ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, serde::Serialize, Hash)]
|
||||||
|
pub enum ReconPermissionScope {
|
||||||
|
#[serde(rename = "R")]
|
||||||
|
Read = 0,
|
||||||
|
#[serde(rename = "RW")]
|
||||||
|
Write = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<PermissionScope> for ReconPermissionScope {
|
||||||
|
fn from(scope: PermissionScope) -> Self {
|
||||||
|
match scope {
|
||||||
|
PermissionScope::Read => Self::Read,
|
||||||
|
PermissionScope::Write => Self::Write,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
use common_utils::events::{ApiEventMetric, ApiEventsType};
|
use common_utils::events::{ApiEventMetric, ApiEventsType};
|
||||||
|
use masking::PeekInterface;
|
||||||
|
|
||||||
use crate::recon::{ReconStatusResponse, ReconTokenResponse, ReconUpdateMerchantRequest};
|
use crate::recon::{
|
||||||
|
ReconStatusResponse, ReconTokenResponse, ReconUpdateMerchantRequest, VerifyTokenResponse,
|
||||||
|
};
|
||||||
|
|
||||||
impl ApiEventMetric for ReconUpdateMerchantRequest {
|
impl ApiEventMetric for ReconUpdateMerchantRequest {
|
||||||
fn get_api_event_type(&self) -> Option<ApiEventsType> {
|
fn get_api_event_type(&self) -> Option<ApiEventsType> {
|
||||||
@ -19,3 +22,11 @@ impl ApiEventMetric for ReconStatusResponse {
|
|||||||
Some(ApiEventsType::Recon)
|
Some(ApiEventsType::Recon)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ApiEventMetric for VerifyTokenResponse {
|
||||||
|
fn get_api_event_type(&self) -> Option<ApiEventsType> {
|
||||||
|
Some(ApiEventsType::User {
|
||||||
|
user_id: self.user_email.peek().to_string(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,11 +1,7 @@
|
|||||||
use common_utils::events::{ApiEventMetric, ApiEventsType};
|
use common_utils::events::{ApiEventMetric, ApiEventsType};
|
||||||
#[cfg(feature = "recon")]
|
|
||||||
use masking::PeekInterface;
|
|
||||||
|
|
||||||
#[cfg(feature = "dummy_connector")]
|
#[cfg(feature = "dummy_connector")]
|
||||||
use crate::user::sample_data::SampleDataRequest;
|
use crate::user::sample_data::SampleDataRequest;
|
||||||
#[cfg(feature = "recon")]
|
|
||||||
use crate::user::VerifyTokenResponse;
|
|
||||||
use crate::user::{
|
use crate::user::{
|
||||||
dashboard_metadata::{
|
dashboard_metadata::{
|
||||||
GetMetaDataRequest, GetMetaDataResponse, GetMultipleMetaDataPayload, SetMetaDataRequest,
|
GetMetaDataRequest, GetMetaDataResponse, GetMultipleMetaDataPayload, SetMetaDataRequest,
|
||||||
@ -23,15 +19,6 @@ use crate::user::{
|
|||||||
VerifyTotpRequest,
|
VerifyTotpRequest,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "recon")]
|
|
||||||
impl ApiEventMetric for VerifyTokenResponse {
|
|
||||||
fn get_api_event_type(&self) -> Option<ApiEventsType> {
|
|
||||||
Some(ApiEventsType::User {
|
|
||||||
user_id: self.user_email.peek().to_string(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
common_utils::impl_api_event_type!(
|
common_utils::impl_api_event_type!(
|
||||||
Miscellaneous,
|
Miscellaneous,
|
||||||
(
|
(
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
use common_utils::pii;
|
use common_utils::{id_type, pii};
|
||||||
use masking::Secret;
|
use masking::Secret;
|
||||||
|
|
||||||
use crate::enums;
|
use crate::enums;
|
||||||
@ -18,3 +18,11 @@ pub struct ReconTokenResponse {
|
|||||||
pub struct ReconStatusResponse {
|
pub struct ReconStatusResponse {
|
||||||
pub recon_status: enums::ReconStatus,
|
pub recon_status: enums::ReconStatus,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(serde::Serialize, Debug)]
|
||||||
|
pub struct VerifyTokenResponse {
|
||||||
|
pub merchant_id: id_type::MerchantId,
|
||||||
|
pub user_email: pii::Email,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub acl: Option<String>,
|
||||||
|
}
|
||||||
|
|||||||
@ -167,13 +167,6 @@ pub struct SendVerifyEmailRequest {
|
|||||||
pub email: pii::Email,
|
pub email: pii::Email,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "recon")]
|
|
||||||
#[derive(serde::Serialize, Debug)]
|
|
||||||
pub struct VerifyTokenResponse {
|
|
||||||
pub merchant_id: id_type::MerchantId,
|
|
||||||
pub user_email: pii::Email,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, serde::Deserialize, serde::Serialize)]
|
#[derive(Debug, serde::Deserialize, serde::Serialize)]
|
||||||
pub struct UpdateUserAccountDetailsRequest {
|
pub struct UpdateUserAccountDetailsRequest {
|
||||||
pub name: Option<Secret<String>>,
|
pub name: Option<Secret<String>>,
|
||||||
|
|||||||
@ -2819,9 +2819,15 @@ pub enum PermissionGroup {
|
|||||||
MerchantDetailsManage,
|
MerchantDetailsManage,
|
||||||
// TODO: To be deprecated, make sure DB is migrated before removing
|
// TODO: To be deprecated, make sure DB is migrated before removing
|
||||||
OrganizationManage,
|
OrganizationManage,
|
||||||
ReconOps,
|
|
||||||
AccountView,
|
AccountView,
|
||||||
AccountManage,
|
AccountManage,
|
||||||
|
ReconReportsView,
|
||||||
|
ReconReportsManage,
|
||||||
|
ReconOpsView,
|
||||||
|
// Alias is added for backward compatibility with database
|
||||||
|
// TODO: Remove alias post migration
|
||||||
|
#[serde(alias = "recon_ops")]
|
||||||
|
ReconOpsManage,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, serde::Serialize, PartialEq, Eq, Hash, strum::EnumIter)]
|
#[derive(Clone, Debug, serde::Serialize, PartialEq, Eq, Hash, strum::EnumIter)]
|
||||||
@ -2831,7 +2837,8 @@ pub enum ParentGroup {
|
|||||||
Workflows,
|
Workflows,
|
||||||
Analytics,
|
Analytics,
|
||||||
Users,
|
Users,
|
||||||
Recon,
|
ReconOps,
|
||||||
|
ReconReports,
|
||||||
Account,
|
Account,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2854,7 +2861,13 @@ pub enum Resource {
|
|||||||
WebhookEvent,
|
WebhookEvent,
|
||||||
Payout,
|
Payout,
|
||||||
Report,
|
Report,
|
||||||
Recon,
|
ReconToken,
|
||||||
|
ReconFiles,
|
||||||
|
ReconAndSettlementAnalytics,
|
||||||
|
ReconUpload,
|
||||||
|
ReconReports,
|
||||||
|
RunRecon,
|
||||||
|
ReconConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, serde::Serialize, Hash)]
|
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, serde::Serialize, Hash)]
|
||||||
|
|||||||
@ -1,24 +1,37 @@
|
|||||||
use api_models::recon as recon_api;
|
use api_models::recon as recon_api;
|
||||||
|
#[cfg(feature = "email")]
|
||||||
use common_utils::ext_traits::AsyncExt;
|
use common_utils::ext_traits::AsyncExt;
|
||||||
use error_stack::ResultExt;
|
use error_stack::ResultExt;
|
||||||
|
#[cfg(feature = "email")]
|
||||||
use masking::{ExposeInterface, PeekInterface, Secret};
|
use masking::{ExposeInterface, PeekInterface, Secret};
|
||||||
|
|
||||||
|
#[cfg(feature = "email")]
|
||||||
|
use crate::{consts, services::email::types as email_types, types::domain};
|
||||||
use crate::{
|
use crate::{
|
||||||
consts,
|
core::errors::{self, RouterResponse, UserErrors, UserResponse},
|
||||||
core::errors::{self, RouterResponse, UserErrors},
|
services::{api as service_api, authentication},
|
||||||
services::{api as service_api, authentication, email::types as email_types},
|
|
||||||
types::{
|
types::{
|
||||||
api::{self as api_types, enums},
|
api::{self as api_types, enums},
|
||||||
domain, storage,
|
storage,
|
||||||
transformers::ForeignTryFrom,
|
transformers::ForeignTryFrom,
|
||||||
},
|
},
|
||||||
SessionState,
|
SessionState,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[allow(unused_variables)]
|
||||||
pub async fn send_recon_request(
|
pub async fn send_recon_request(
|
||||||
state: SessionState,
|
state: SessionState,
|
||||||
auth_data: authentication::AuthenticationDataWithUser,
|
auth_data: authentication::AuthenticationDataWithUser,
|
||||||
) -> RouterResponse<recon_api::ReconStatusResponse> {
|
) -> RouterResponse<recon_api::ReconStatusResponse> {
|
||||||
|
#[cfg(not(feature = "email"))]
|
||||||
|
return Ok(service_api::ApplicationResponse::Json(
|
||||||
|
recon_api::ReconStatusResponse {
|
||||||
|
recon_status: enums::ReconStatus::NotRequested,
|
||||||
|
},
|
||||||
|
));
|
||||||
|
|
||||||
|
#[cfg(feature = "email")]
|
||||||
|
{
|
||||||
let user_in_db = &auth_data.user;
|
let user_in_db = &auth_data.user;
|
||||||
let merchant_id = auth_data.merchant_account.get_id().clone();
|
let merchant_id = auth_data.merchant_account.get_id().clone();
|
||||||
|
|
||||||
@ -37,14 +50,12 @@ pub async fn send_recon_request(
|
|||||||
)
|
)
|
||||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||||
.attach_printable("Failed to convert recipient's email to UserEmail")?,
|
.attach_printable("Failed to convert recipient's email to UserEmail")?,
|
||||||
settings: state.conf.clone(),
|
|
||||||
subject: format!(
|
subject: format!(
|
||||||
"{} {}",
|
"{} {}",
|
||||||
consts::EMAIL_SUBJECT_DASHBOARD_FEATURE_REQUEST,
|
consts::EMAIL_SUBJECT_DASHBOARD_FEATURE_REQUEST,
|
||||||
user_email.expose().peek()
|
user_email.expose().peek()
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
state
|
state
|
||||||
.email_client
|
.email_client
|
||||||
.compose_and_send_email(
|
.compose_and_send_email(
|
||||||
@ -81,20 +92,22 @@ pub async fn send_recon_request(
|
|||||||
))
|
))
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn generate_recon_token(
|
pub async fn generate_recon_token(
|
||||||
state: SessionState,
|
state: SessionState,
|
||||||
user: authentication::UserFromToken,
|
user_with_role: authentication::UserFromTokenWithRoleInfo,
|
||||||
) -> RouterResponse<recon_api::ReconTokenResponse> {
|
) -> RouterResponse<recon_api::ReconTokenResponse> {
|
||||||
let token = authentication::AuthToken::new_token(
|
let user = user_with_role.user;
|
||||||
|
let token = authentication::ReconToken::new_token(
|
||||||
user.user_id.clone(),
|
user.user_id.clone(),
|
||||||
user.merchant_id.clone(),
|
user.merchant_id.clone(),
|
||||||
user.role_id.clone(),
|
|
||||||
&state.conf,
|
&state.conf,
|
||||||
user.org_id.clone(),
|
user.org_id.clone(),
|
||||||
user.profile_id.clone(),
|
user.profile_id.clone(),
|
||||||
user.tenant_id,
|
user.tenant_id,
|
||||||
|
user_with_role.role_info,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||||
@ -138,18 +151,20 @@ pub async fn recon_merchant_account_update(
|
|||||||
format!("Failed while updating merchant's recon status: {merchant_id:?}")
|
format!("Failed while updating merchant's recon status: {merchant_id:?}")
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
#[cfg(feature = "email")]
|
||||||
|
{
|
||||||
let user_email = &req.user_email.clone();
|
let user_email = &req.user_email.clone();
|
||||||
let email_contents = email_types::ReconActivation {
|
let email_contents = email_types::ReconActivation {
|
||||||
recipient_email: domain::UserEmail::from_pii_email(user_email.clone())
|
recipient_email: domain::UserEmail::from_pii_email(user_email.clone())
|
||||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||||
.attach_printable("Failed to convert recipient's email to UserEmail from pii::Email")?,
|
.attach_printable(
|
||||||
|
"Failed to convert recipient's email to UserEmail from pii::Email",
|
||||||
|
)?,
|
||||||
user_name: domain::UserName::new(Secret::new("HyperSwitch User".to_string()))
|
user_name: domain::UserName::new(Secret::new("HyperSwitch User".to_string()))
|
||||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||||
.attach_printable("Failed to form username")?,
|
.attach_printable("Failed to form username")?,
|
||||||
settings: state.conf.clone(),
|
|
||||||
subject: consts::EMAIL_SUBJECT_APPROVAL_RECON_REQUEST,
|
subject: consts::EMAIL_SUBJECT_APPROVAL_RECON_REQUEST,
|
||||||
};
|
};
|
||||||
|
|
||||||
if req.recon_status == enums::ReconStatus::Active {
|
if req.recon_status == enums::ReconStatus::Active {
|
||||||
let _ = state
|
let _ = state
|
||||||
.email_client
|
.email_client
|
||||||
@ -158,9 +173,15 @@ pub async fn recon_merchant_account_update(
|
|||||||
state.conf.proxy.https_url.as_ref(),
|
state.conf.proxy.https_url.as_ref(),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
|
.inspect_err(|err| {
|
||||||
|
router_env::logger::error!(
|
||||||
|
"Failed to compose and send email notifying them of recon activation: {}",
|
||||||
|
err
|
||||||
|
)
|
||||||
|
})
|
||||||
.change_context(UserErrors::InternalServerError)
|
.change_context(UserErrors::InternalServerError)
|
||||||
.attach_printable("Failed to compose and send email for ReconActivation")
|
.attach_printable("Failed to compose and send email for ReconActivation");
|
||||||
.is_ok();
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(service_api::ApplicationResponse::Json(
|
Ok(service_api::ApplicationResponse::Json(
|
||||||
@ -170,3 +191,34 @@ pub async fn recon_merchant_account_update(
|
|||||||
})?,
|
})?,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn verify_recon_token(
|
||||||
|
state: SessionState,
|
||||||
|
user_with_role: authentication::UserFromTokenWithRoleInfo,
|
||||||
|
) -> UserResponse<recon_api::VerifyTokenResponse> {
|
||||||
|
let user = user_with_role.user;
|
||||||
|
let user_in_db = user
|
||||||
|
.get_user_from_db(&state)
|
||||||
|
.await
|
||||||
|
.attach_printable_lazy(|| {
|
||||||
|
format!(
|
||||||
|
"Failed to fetch the user from DB for user_id - {}",
|
||||||
|
user.user_id
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let acl = user_with_role.role_info.get_recon_acl();
|
||||||
|
let optional_acl_str = serde_json::to_string(&acl)
|
||||||
|
.inspect_err(|err| router_env::logger::error!("Failed to serialize acl to string: {}", err))
|
||||||
|
.change_context(UserErrors::InternalServerError)
|
||||||
|
.attach_printable("Failed to serialize acl to string. Using empty ACL")
|
||||||
|
.ok();
|
||||||
|
|
||||||
|
Ok(service_api::ApplicationResponse::Json(
|
||||||
|
recon_api::VerifyTokenResponse {
|
||||||
|
merchant_id: user.merchant_id.to_owned(),
|
||||||
|
user_email: user_in_db.0.email,
|
||||||
|
acl: optional_acl_str,
|
||||||
|
},
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|||||||
@ -1593,27 +1593,6 @@ pub async fn send_verification_mail(
|
|||||||
Ok(ApplicationResponse::StatusOk)
|
Ok(ApplicationResponse::StatusOk)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "recon")]
|
|
||||||
pub async fn verify_token(
|
|
||||||
state: SessionState,
|
|
||||||
user: auth::UserFromToken,
|
|
||||||
) -> UserResponse<user_api::VerifyTokenResponse> {
|
|
||||||
let user_in_db = user
|
|
||||||
.get_user_from_db(&state)
|
|
||||||
.await
|
|
||||||
.attach_printable_lazy(|| {
|
|
||||||
format!(
|
|
||||||
"Failed to fetch the user from DB for user_id - {}",
|
|
||||||
user.user_id
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(ApplicationResponse::Json(user_api::VerifyTokenResponse {
|
|
||||||
merchant_id: user.merchant_id.to_owned(),
|
|
||||||
user_email: user_in_db.0.email,
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn update_user_details(
|
pub async fn update_user_details(
|
||||||
state: SessionState,
|
state: SessionState,
|
||||||
user_token: auth::UserFromToken,
|
user_token: auth::UserFromToken,
|
||||||
|
|||||||
@ -1216,7 +1216,10 @@ impl Recon {
|
|||||||
.service(
|
.service(
|
||||||
web::resource("/request").route(web::post().to(recon_routes::request_for_recon)),
|
web::resource("/request").route(web::post().to(recon_routes::request_for_recon)),
|
||||||
)
|
)
|
||||||
.service(web::resource("/verify_token").route(web::get().to(user::verify_recon_token)))
|
.service(
|
||||||
|
web::resource("/verify_token")
|
||||||
|
.route(web::get().to(recon_routes::verify_recon_token)),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -38,7 +38,7 @@ pub async fn request_for_recon(state: web::Data<AppState>, http_req: HttpRequest
|
|||||||
(),
|
(),
|
||||||
|state, user, _, _| recon::send_recon_request(state, user),
|
|state, user, _, _| recon::send_recon_request(state, user),
|
||||||
&authentication::JWTAuth {
|
&authentication::JWTAuth {
|
||||||
permission: Permission::MerchantReconWrite,
|
permission: Permission::MerchantAccountWrite,
|
||||||
},
|
},
|
||||||
api_locking::LockAction::NotApplicable,
|
api_locking::LockAction::NotApplicable,
|
||||||
))
|
))
|
||||||
@ -54,7 +54,24 @@ pub async fn get_recon_token(state: web::Data<AppState>, req: HttpRequest) -> Ht
|
|||||||
(),
|
(),
|
||||||
|state, user, _, _| recon::generate_recon_token(state, user),
|
|state, user, _, _| recon::generate_recon_token(state, user),
|
||||||
&authentication::JWTAuth {
|
&authentication::JWTAuth {
|
||||||
permission: Permission::MerchantReconWrite,
|
permission: Permission::MerchantReconTokenRead,
|
||||||
|
},
|
||||||
|
api_locking::LockAction::NotApplicable,
|
||||||
|
))
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "recon")]
|
||||||
|
pub async fn verify_recon_token(state: web::Data<AppState>, http_req: HttpRequest) -> HttpResponse {
|
||||||
|
let flow = Flow::ReconVerifyToken;
|
||||||
|
Box::pin(api::server_wrap(
|
||||||
|
flow,
|
||||||
|
state.clone(),
|
||||||
|
&http_req,
|
||||||
|
(),
|
||||||
|
|state, user, _req, _| recon::verify_recon_token(state, user),
|
||||||
|
&authentication::JWTAuth {
|
||||||
|
permission: Permission::MerchantReconTokenRead,
|
||||||
},
|
},
|
||||||
api_locking::LockAction::NotApplicable,
|
api_locking::LockAction::NotApplicable,
|
||||||
))
|
))
|
||||||
|
|||||||
@ -487,23 +487,6 @@ pub async fn verify_email_request(
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "recon")]
|
|
||||||
pub async fn verify_recon_token(state: web::Data<AppState>, http_req: HttpRequest) -> HttpResponse {
|
|
||||||
let flow = Flow::ReconVerifyToken;
|
|
||||||
Box::pin(api::server_wrap(
|
|
||||||
flow,
|
|
||||||
state.clone(),
|
|
||||||
&http_req,
|
|
||||||
(),
|
|
||||||
|state, user, _req, _| user_core::verify_token(state, user),
|
|
||||||
&auth::JWTAuth {
|
|
||||||
permission: Permission::MerchantReconWrite,
|
|
||||||
},
|
|
||||||
api_locking::LockAction::NotApplicable,
|
|
||||||
))
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn update_user_account_details(
|
pub async fn update_user_account_details(
|
||||||
state: web::Data<AppState>,
|
state: web::Data<AppState>,
|
||||||
req: HttpRequest,
|
req: HttpRequest,
|
||||||
|
|||||||
@ -90,6 +90,12 @@ pub struct AuthenticationDataWithUser {
|
|||||||
pub profile_id: id_type::ProfileId,
|
pub profile_id: id_type::ProfileId,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct UserFromTokenWithRoleInfo {
|
||||||
|
pub user: UserFromToken,
|
||||||
|
pub role_info: authorization::roles::RoleInfo,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
||||||
#[serde(
|
#[serde(
|
||||||
tag = "api_auth_type",
|
tag = "api_auth_type",
|
||||||
@ -3228,3 +3234,91 @@ where
|
|||||||
Ok((auth, auth_type))
|
Ok((auth, auth_type))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "recon")]
|
||||||
|
#[async_trait]
|
||||||
|
impl<A> AuthenticateAndFetch<UserFromTokenWithRoleInfo, A> for JWTAuth
|
||||||
|
where
|
||||||
|
A: SessionStateInfo + Sync,
|
||||||
|
{
|
||||||
|
async fn authenticate_and_fetch(
|
||||||
|
&self,
|
||||||
|
request_headers: &HeaderMap,
|
||||||
|
state: &A,
|
||||||
|
) -> RouterResult<(UserFromTokenWithRoleInfo, AuthenticationType)> {
|
||||||
|
let payload = parse_jwt_payload::<A, AuthToken>(request_headers, state).await?;
|
||||||
|
if payload.check_in_blacklist(state).await? {
|
||||||
|
return Err(errors::ApiErrorResponse::InvalidJwtToken.into());
|
||||||
|
}
|
||||||
|
authorization::check_tenant(
|
||||||
|
payload.tenant_id.clone(),
|
||||||
|
&state.session_state().tenant.tenant_id,
|
||||||
|
)?;
|
||||||
|
let role_info = authorization::get_role_info(state, &payload).await?;
|
||||||
|
authorization::check_permission(&self.permission, &role_info)?;
|
||||||
|
|
||||||
|
let user = UserFromToken {
|
||||||
|
user_id: payload.user_id.clone(),
|
||||||
|
merchant_id: payload.merchant_id.clone(),
|
||||||
|
org_id: payload.org_id,
|
||||||
|
role_id: payload.role_id,
|
||||||
|
profile_id: payload.profile_id,
|
||||||
|
tenant_id: payload.tenant_id,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok((
|
||||||
|
UserFromTokenWithRoleInfo { user, role_info },
|
||||||
|
AuthenticationType::MerchantJwt {
|
||||||
|
merchant_id: payload.merchant_id,
|
||||||
|
user_id: Some(payload.user_id),
|
||||||
|
},
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "recon")]
|
||||||
|
#[derive(serde::Serialize, serde::Deserialize)]
|
||||||
|
pub struct ReconToken {
|
||||||
|
pub user_id: String,
|
||||||
|
pub merchant_id: id_type::MerchantId,
|
||||||
|
pub role_id: String,
|
||||||
|
pub exp: u64,
|
||||||
|
pub org_id: id_type::OrganizationId,
|
||||||
|
pub profile_id: id_type::ProfileId,
|
||||||
|
pub tenant_id: Option<id_type::TenantId>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub acl: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(feature = "olap", feature = "recon"))]
|
||||||
|
impl ReconToken {
|
||||||
|
pub async fn new_token(
|
||||||
|
user_id: String,
|
||||||
|
merchant_id: id_type::MerchantId,
|
||||||
|
settings: &Settings,
|
||||||
|
org_id: id_type::OrganizationId,
|
||||||
|
profile_id: id_type::ProfileId,
|
||||||
|
tenant_id: Option<id_type::TenantId>,
|
||||||
|
role_info: authorization::roles::RoleInfo,
|
||||||
|
) -> UserResult<String> {
|
||||||
|
let exp_duration = std::time::Duration::from_secs(consts::JWT_TOKEN_TIME_IN_SECS);
|
||||||
|
let exp = jwt::generate_exp(exp_duration)?.as_secs();
|
||||||
|
let acl = role_info.get_recon_acl();
|
||||||
|
let optional_acl_str = serde_json::to_string(&acl)
|
||||||
|
.inspect_err(|err| logger::error!("Failed to serialize acl to string: {}", err))
|
||||||
|
.change_context(errors::UserErrors::InternalServerError)
|
||||||
|
.attach_printable("Failed to serialize acl to string. Using empty ACL")
|
||||||
|
.ok();
|
||||||
|
let token_payload = Self {
|
||||||
|
user_id,
|
||||||
|
merchant_id,
|
||||||
|
role_id: role_info.get_role_id().to_string(),
|
||||||
|
exp,
|
||||||
|
org_id,
|
||||||
|
profile_id,
|
||||||
|
tenant_id,
|
||||||
|
acl: optional_acl_str,
|
||||||
|
};
|
||||||
|
jwt::generate_jwt(&token_payload, settings).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -40,7 +40,10 @@ fn get_group_description(group: PermissionGroup) -> &'static str {
|
|||||||
PermissionGroup::MerchantDetailsView | PermissionGroup::AccountView => "View Merchant Details",
|
PermissionGroup::MerchantDetailsView | PermissionGroup::AccountView => "View Merchant Details",
|
||||||
PermissionGroup::MerchantDetailsManage | PermissionGroup::AccountManage => "Create, modify and delete Merchant Details like api keys, webhooks, etc",
|
PermissionGroup::MerchantDetailsManage | PermissionGroup::AccountManage => "Create, modify and delete Merchant Details like api keys, webhooks, etc",
|
||||||
PermissionGroup::OrganizationManage => "Manage organization level tasks like create new Merchant accounts, Organization level roles, etc",
|
PermissionGroup::OrganizationManage => "Manage organization level tasks like create new Merchant accounts, Organization level roles, etc",
|
||||||
PermissionGroup::ReconOps => "View and manage reconciliation reports",
|
PermissionGroup::ReconReportsView => "View and access reconciliation reports and analytics",
|
||||||
|
PermissionGroup::ReconReportsManage => "Manage reconciliation reports",
|
||||||
|
PermissionGroup::ReconOpsView => "View and access reconciliation operations",
|
||||||
|
PermissionGroup::ReconOpsManage => "Manage reconciliation operations",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,6 +55,7 @@ pub fn get_parent_group_description(group: ParentGroup) -> &'static str {
|
|||||||
ParentGroup::Analytics => "View Analytics",
|
ParentGroup::Analytics => "View Analytics",
|
||||||
ParentGroup::Users => "Manage and invite Users to the Team",
|
ParentGroup::Users => "Manage and invite Users to the Team",
|
||||||
ParentGroup::Account => "Create, modify and delete Merchant Details like api keys, webhooks, etc",
|
ParentGroup::Account => "Create, modify and delete Merchant Details like api keys, webhooks, etc",
|
||||||
ParentGroup::Recon => "View and manage reconciliation reports",
|
ParentGroup::ReconOps => "View, manage reconciliation operations like upload and process files, run reconciliation etc",
|
||||||
|
ParentGroup::ReconReports => "View, manage reconciliation reports and analytics",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,7 +21,9 @@ impl PermissionGroupExt for PermissionGroup {
|
|||||||
| Self::AnalyticsView
|
| Self::AnalyticsView
|
||||||
| Self::UsersView
|
| Self::UsersView
|
||||||
| Self::MerchantDetailsView
|
| Self::MerchantDetailsView
|
||||||
| Self::AccountView => PermissionScope::Read,
|
| Self::AccountView
|
||||||
|
| Self::ReconOpsView
|
||||||
|
| Self::ReconReportsView => PermissionScope::Read,
|
||||||
|
|
||||||
Self::OperationsManage
|
Self::OperationsManage
|
||||||
| Self::ConnectorsManage
|
| Self::ConnectorsManage
|
||||||
@ -29,8 +31,9 @@ impl PermissionGroupExt for PermissionGroup {
|
|||||||
| Self::UsersManage
|
| Self::UsersManage
|
||||||
| Self::MerchantDetailsManage
|
| Self::MerchantDetailsManage
|
||||||
| Self::OrganizationManage
|
| Self::OrganizationManage
|
||||||
| Self::ReconOps
|
| Self::AccountManage
|
||||||
| Self::AccountManage => PermissionScope::Write,
|
| Self::ReconOpsManage
|
||||||
|
| Self::ReconReportsManage => PermissionScope::Write,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,12 +44,13 @@ impl PermissionGroupExt for PermissionGroup {
|
|||||||
Self::WorkflowsView | Self::WorkflowsManage => ParentGroup::Workflows,
|
Self::WorkflowsView | Self::WorkflowsManage => ParentGroup::Workflows,
|
||||||
Self::AnalyticsView => ParentGroup::Analytics,
|
Self::AnalyticsView => ParentGroup::Analytics,
|
||||||
Self::UsersView | Self::UsersManage => ParentGroup::Users,
|
Self::UsersView | Self::UsersManage => ParentGroup::Users,
|
||||||
Self::ReconOps => ParentGroup::Recon,
|
|
||||||
Self::MerchantDetailsView
|
Self::MerchantDetailsView
|
||||||
| Self::OrganizationManage
|
| Self::OrganizationManage
|
||||||
| Self::MerchantDetailsManage
|
| Self::MerchantDetailsManage
|
||||||
| Self::AccountView
|
| Self::AccountView
|
||||||
| Self::AccountManage => ParentGroup::Account,
|
| Self::AccountManage => ParentGroup::Account,
|
||||||
|
Self::ReconOpsView | Self::ReconOpsManage => ParentGroup::ReconOps,
|
||||||
|
Self::ReconReportsView | Self::ReconReportsManage => ParentGroup::ReconReports,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,7 +80,11 @@ impl PermissionGroupExt for PermissionGroup {
|
|||||||
vec![Self::UsersView, Self::UsersManage]
|
vec![Self::UsersView, Self::UsersManage]
|
||||||
}
|
}
|
||||||
|
|
||||||
Self::ReconOps => vec![Self::ReconOps],
|
Self::ReconOpsView => vec![Self::ReconOpsView],
|
||||||
|
Self::ReconOpsManage => vec![Self::ReconOpsView, Self::ReconOpsManage],
|
||||||
|
|
||||||
|
Self::ReconReportsView => vec![Self::ReconReportsView],
|
||||||
|
Self::ReconReportsManage => vec![Self::ReconReportsView, Self::ReconReportsManage],
|
||||||
|
|
||||||
Self::MerchantDetailsView => vec![Self::MerchantDetailsView],
|
Self::MerchantDetailsView => vec![Self::MerchantDetailsView],
|
||||||
Self::MerchantDetailsManage => {
|
Self::MerchantDetailsManage => {
|
||||||
@ -108,7 +116,8 @@ impl ParentGroupExt for ParentGroup {
|
|||||||
Self::Analytics => ANALYTICS.to_vec(),
|
Self::Analytics => ANALYTICS.to_vec(),
|
||||||
Self::Users => USERS.to_vec(),
|
Self::Users => USERS.to_vec(),
|
||||||
Self::Account => ACCOUNT.to_vec(),
|
Self::Account => ACCOUNT.to_vec(),
|
||||||
Self::Recon => RECON.to_vec(),
|
Self::ReconOps => RECON_OPS.to_vec(),
|
||||||
|
Self::ReconReports => RECON_REPORTS.to_vec(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,4 +176,18 @@ pub static USERS: [Resource; 2] = [Resource::User, Resource::Account];
|
|||||||
|
|
||||||
pub static ACCOUNT: [Resource; 3] = [Resource::Account, Resource::ApiKey, Resource::WebhookEvent];
|
pub static ACCOUNT: [Resource; 3] = [Resource::Account, Resource::ApiKey, Resource::WebhookEvent];
|
||||||
|
|
||||||
pub static RECON: [Resource; 1] = [Resource::Recon];
|
pub static RECON_OPS: [Resource; 7] = [
|
||||||
|
Resource::ReconToken,
|
||||||
|
Resource::ReconFiles,
|
||||||
|
Resource::ReconUpload,
|
||||||
|
Resource::RunRecon,
|
||||||
|
Resource::ReconConfig,
|
||||||
|
Resource::ReconAndSettlementAnalytics,
|
||||||
|
Resource::ReconReports,
|
||||||
|
];
|
||||||
|
|
||||||
|
pub static RECON_REPORTS: [Resource; 3] = [
|
||||||
|
Resource::ReconToken,
|
||||||
|
Resource::ReconAndSettlementAnalytics,
|
||||||
|
Resource::ReconReports,
|
||||||
|
];
|
||||||
|
|||||||
@ -67,8 +67,32 @@ generate_permissions! {
|
|||||||
scopes: [Read, Write],
|
scopes: [Read, Write],
|
||||||
entities: [Merchant]
|
entities: [Merchant]
|
||||||
},
|
},
|
||||||
Recon: {
|
ReconToken: {
|
||||||
scopes: [Write],
|
scopes: [Read],
|
||||||
|
entities: [Merchant]
|
||||||
|
},
|
||||||
|
ReconFiles: {
|
||||||
|
scopes: [Read, Write],
|
||||||
|
entities: [Merchant]
|
||||||
|
},
|
||||||
|
ReconAndSettlementAnalytics: {
|
||||||
|
scopes: [Read],
|
||||||
|
entities: [Merchant]
|
||||||
|
},
|
||||||
|
ReconUpload: {
|
||||||
|
scopes: [Read, Write],
|
||||||
|
entities: [Merchant]
|
||||||
|
},
|
||||||
|
ReconReports: {
|
||||||
|
scopes: [Read, Write],
|
||||||
|
entities: [Merchant]
|
||||||
|
},
|
||||||
|
RunRecon: {
|
||||||
|
scopes: [Read, Write],
|
||||||
|
entities: [Merchant]
|
||||||
|
},
|
||||||
|
ReconConfig: {
|
||||||
|
scopes: [Read, Write],
|
||||||
entities: [Merchant]
|
entities: [Merchant]
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
@ -91,7 +115,13 @@ pub fn get_resource_name(resource: &Resource, entity_type: &EntityType) -> &'sta
|
|||||||
(Resource::Report, _) => "Operation Reports",
|
(Resource::Report, _) => "Operation Reports",
|
||||||
(Resource::User, _) => "Users",
|
(Resource::User, _) => "Users",
|
||||||
(Resource::WebhookEvent, _) => "Webhook Events",
|
(Resource::WebhookEvent, _) => "Webhook Events",
|
||||||
(Resource::Recon, _) => "Reconciliation Reports",
|
(Resource::ReconUpload, _) => "Reconciliation File Upload",
|
||||||
|
(Resource::RunRecon, _) => "Run Reconciliation Process",
|
||||||
|
(Resource::ReconConfig, _) => "Reconciliation Configurations",
|
||||||
|
(Resource::ReconToken, _) => "Generate & Verify Reconciliation Token",
|
||||||
|
(Resource::ReconFiles, _) => "Reconciliation Process Manager",
|
||||||
|
(Resource::ReconReports, _) => "Reconciliation Reports",
|
||||||
|
(Resource::ReconAndSettlementAnalytics, _) => "Reconciliation Analytics",
|
||||||
(Resource::Account, EntityType::Profile) => "Business Profile Account",
|
(Resource::Account, EntityType::Profile) => "Business Profile Account",
|
||||||
(Resource::Account, EntityType::Merchant) => "Merchant Account",
|
(Resource::Account, EntityType::Merchant) => "Merchant Account",
|
||||||
(Resource::Account, EntityType::Organization) => "Organization Account",
|
(Resource::Account, EntityType::Organization) => "Organization Account",
|
||||||
|
|||||||
@ -1,8 +1,14 @@
|
|||||||
|
#[cfg(feature = "recon")]
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
#[cfg(feature = "recon")]
|
||||||
|
use api_models::enums::ReconPermissionScope;
|
||||||
use common_enums::{EntityType, PermissionGroup, Resource, RoleScope};
|
use common_enums::{EntityType, PermissionGroup, Resource, RoleScope};
|
||||||
use common_utils::{errors::CustomResult, id_type};
|
use common_utils::{errors::CustomResult, id_type};
|
||||||
|
|
||||||
|
#[cfg(feature = "recon")]
|
||||||
|
use super::permission_groups::{RECON_OPS, RECON_REPORTS};
|
||||||
use super::{permission_groups::PermissionGroupExt, permissions::Permission};
|
use super::{permission_groups::PermissionGroupExt, permissions::Permission};
|
||||||
use crate::{core::errors, routes::SessionState};
|
use crate::{core::errors, routes::SessionState};
|
||||||
|
|
||||||
@ -78,6 +84,38 @@ impl RoleInfo {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "recon")]
|
||||||
|
pub fn get_recon_acl(&self) -> HashMap<Resource, ReconPermissionScope> {
|
||||||
|
let mut acl: HashMap<Resource, ReconPermissionScope> = HashMap::new();
|
||||||
|
let mut recon_resources = RECON_OPS.to_vec();
|
||||||
|
recon_resources.extend(RECON_REPORTS);
|
||||||
|
let recon_internal_resources = [Resource::ReconToken];
|
||||||
|
self.get_permission_groups()
|
||||||
|
.iter()
|
||||||
|
.for_each(|permission_group| {
|
||||||
|
permission_group.resources().iter().for_each(|resource| {
|
||||||
|
if recon_resources.contains(resource)
|
||||||
|
&& !recon_internal_resources.contains(resource)
|
||||||
|
{
|
||||||
|
let scope = match resource {
|
||||||
|
Resource::ReconAndSettlementAnalytics => ReconPermissionScope::Read,
|
||||||
|
_ => ReconPermissionScope::from(permission_group.scope()),
|
||||||
|
};
|
||||||
|
acl.entry(*resource)
|
||||||
|
.and_modify(|curr_scope| {
|
||||||
|
*curr_scope = if (*curr_scope) < scope {
|
||||||
|
scope
|
||||||
|
} else {
|
||||||
|
*curr_scope
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.or_insert(scope);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
acl
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn from_role_id_in_merchant_scope(
|
pub async fn from_role_id_in_merchant_scope(
|
||||||
state: &SessionState,
|
state: &SessionState,
|
||||||
role_id: &str,
|
role_id: &str,
|
||||||
|
|||||||
@ -28,7 +28,10 @@ pub static PREDEFINED_ROLES: Lazy<HashMap<&'static str, RoleInfo>> = Lazy::new(|
|
|||||||
PermissionGroup::MerchantDetailsManage,
|
PermissionGroup::MerchantDetailsManage,
|
||||||
PermissionGroup::AccountManage,
|
PermissionGroup::AccountManage,
|
||||||
PermissionGroup::OrganizationManage,
|
PermissionGroup::OrganizationManage,
|
||||||
PermissionGroup::ReconOps,
|
PermissionGroup::ReconOpsView,
|
||||||
|
PermissionGroup::ReconOpsManage,
|
||||||
|
PermissionGroup::ReconReportsView,
|
||||||
|
PermissionGroup::ReconReportsManage,
|
||||||
],
|
],
|
||||||
role_id: common_utils::consts::ROLE_ID_INTERNAL_ADMIN.to_string(),
|
role_id: common_utils::consts::ROLE_ID_INTERNAL_ADMIN.to_string(),
|
||||||
role_name: "internal_admin".to_string(),
|
role_name: "internal_admin".to_string(),
|
||||||
@ -51,6 +54,8 @@ pub static PREDEFINED_ROLES: Lazy<HashMap<&'static str, RoleInfo>> = Lazy::new(|
|
|||||||
PermissionGroup::UsersView,
|
PermissionGroup::UsersView,
|
||||||
PermissionGroup::MerchantDetailsView,
|
PermissionGroup::MerchantDetailsView,
|
||||||
PermissionGroup::AccountView,
|
PermissionGroup::AccountView,
|
||||||
|
PermissionGroup::ReconOpsView,
|
||||||
|
PermissionGroup::ReconReportsView,
|
||||||
],
|
],
|
||||||
role_id: common_utils::consts::ROLE_ID_INTERNAL_VIEW_ONLY_USER.to_string(),
|
role_id: common_utils::consts::ROLE_ID_INTERNAL_VIEW_ONLY_USER.to_string(),
|
||||||
role_name: "internal_view_only".to_string(),
|
role_name: "internal_view_only".to_string(),
|
||||||
@ -82,7 +87,10 @@ pub static PREDEFINED_ROLES: Lazy<HashMap<&'static str, RoleInfo>> = Lazy::new(|
|
|||||||
PermissionGroup::MerchantDetailsManage,
|
PermissionGroup::MerchantDetailsManage,
|
||||||
PermissionGroup::AccountManage,
|
PermissionGroup::AccountManage,
|
||||||
PermissionGroup::OrganizationManage,
|
PermissionGroup::OrganizationManage,
|
||||||
PermissionGroup::ReconOps,
|
PermissionGroup::ReconOpsView,
|
||||||
|
PermissionGroup::ReconOpsManage,
|
||||||
|
PermissionGroup::ReconReportsView,
|
||||||
|
PermissionGroup::ReconReportsManage,
|
||||||
],
|
],
|
||||||
role_id: common_utils::consts::ROLE_ID_ORGANIZATION_ADMIN.to_string(),
|
role_id: common_utils::consts::ROLE_ID_ORGANIZATION_ADMIN.to_string(),
|
||||||
role_name: "organization_admin".to_string(),
|
role_name: "organization_admin".to_string(),
|
||||||
@ -113,7 +121,10 @@ pub static PREDEFINED_ROLES: Lazy<HashMap<&'static str, RoleInfo>> = Lazy::new(|
|
|||||||
PermissionGroup::AccountView,
|
PermissionGroup::AccountView,
|
||||||
PermissionGroup::MerchantDetailsManage,
|
PermissionGroup::MerchantDetailsManage,
|
||||||
PermissionGroup::AccountManage,
|
PermissionGroup::AccountManage,
|
||||||
PermissionGroup::ReconOps,
|
PermissionGroup::ReconOpsView,
|
||||||
|
PermissionGroup::ReconOpsManage,
|
||||||
|
PermissionGroup::ReconReportsView,
|
||||||
|
PermissionGroup::ReconReportsManage,
|
||||||
],
|
],
|
||||||
role_id: consts::user_role::ROLE_ID_MERCHANT_ADMIN.to_string(),
|
role_id: consts::user_role::ROLE_ID_MERCHANT_ADMIN.to_string(),
|
||||||
role_name: "merchant_admin".to_string(),
|
role_name: "merchant_admin".to_string(),
|
||||||
@ -136,6 +147,8 @@ pub static PREDEFINED_ROLES: Lazy<HashMap<&'static str, RoleInfo>> = Lazy::new(|
|
|||||||
PermissionGroup::UsersView,
|
PermissionGroup::UsersView,
|
||||||
PermissionGroup::MerchantDetailsView,
|
PermissionGroup::MerchantDetailsView,
|
||||||
PermissionGroup::AccountView,
|
PermissionGroup::AccountView,
|
||||||
|
PermissionGroup::ReconOpsView,
|
||||||
|
PermissionGroup::ReconReportsView,
|
||||||
],
|
],
|
||||||
role_id: consts::user_role::ROLE_ID_MERCHANT_VIEW_ONLY.to_string(),
|
role_id: consts::user_role::ROLE_ID_MERCHANT_VIEW_ONLY.to_string(),
|
||||||
role_name: "merchant_view_only".to_string(),
|
role_name: "merchant_view_only".to_string(),
|
||||||
@ -180,6 +193,8 @@ pub static PREDEFINED_ROLES: Lazy<HashMap<&'static str, RoleInfo>> = Lazy::new(|
|
|||||||
PermissionGroup::AccountView,
|
PermissionGroup::AccountView,
|
||||||
PermissionGroup::MerchantDetailsManage,
|
PermissionGroup::MerchantDetailsManage,
|
||||||
PermissionGroup::AccountManage,
|
PermissionGroup::AccountManage,
|
||||||
|
PermissionGroup::ReconOpsView,
|
||||||
|
PermissionGroup::ReconReportsView,
|
||||||
],
|
],
|
||||||
role_id: consts::user_role::ROLE_ID_MERCHANT_DEVELOPER.to_string(),
|
role_id: consts::user_role::ROLE_ID_MERCHANT_DEVELOPER.to_string(),
|
||||||
role_name: "merchant_developer".to_string(),
|
role_name: "merchant_developer".to_string(),
|
||||||
@ -203,6 +218,9 @@ pub static PREDEFINED_ROLES: Lazy<HashMap<&'static str, RoleInfo>> = Lazy::new(|
|
|||||||
PermissionGroup::UsersView,
|
PermissionGroup::UsersView,
|
||||||
PermissionGroup::MerchantDetailsView,
|
PermissionGroup::MerchantDetailsView,
|
||||||
PermissionGroup::AccountView,
|
PermissionGroup::AccountView,
|
||||||
|
PermissionGroup::ReconOpsView,
|
||||||
|
PermissionGroup::ReconOpsManage,
|
||||||
|
PermissionGroup::ReconReportsView,
|
||||||
],
|
],
|
||||||
role_id: consts::user_role::ROLE_ID_MERCHANT_OPERATOR.to_string(),
|
role_id: consts::user_role::ROLE_ID_MERCHANT_OPERATOR.to_string(),
|
||||||
role_name: "merchant_operator".to_string(),
|
role_name: "merchant_operator".to_string(),
|
||||||
@ -223,6 +241,8 @@ pub static PREDEFINED_ROLES: Lazy<HashMap<&'static str, RoleInfo>> = Lazy::new(|
|
|||||||
PermissionGroup::UsersView,
|
PermissionGroup::UsersView,
|
||||||
PermissionGroup::MerchantDetailsView,
|
PermissionGroup::MerchantDetailsView,
|
||||||
PermissionGroup::AccountView,
|
PermissionGroup::AccountView,
|
||||||
|
PermissionGroup::ReconOpsView,
|
||||||
|
PermissionGroup::ReconReportsView,
|
||||||
],
|
],
|
||||||
role_id: consts::user_role::ROLE_ID_MERCHANT_CUSTOMER_SUPPORT.to_string(),
|
role_id: consts::user_role::ROLE_ID_MERCHANT_CUSTOMER_SUPPORT.to_string(),
|
||||||
role_name: "customer_support".to_string(),
|
role_name: "customer_support".to_string(),
|
||||||
|
|||||||
@ -383,7 +383,6 @@ impl EmailData for InviteUser {
|
|||||||
pub struct ReconActivation {
|
pub struct ReconActivation {
|
||||||
pub recipient_email: domain::UserEmail,
|
pub recipient_email: domain::UserEmail,
|
||||||
pub user_name: domain::UserName,
|
pub user_name: domain::UserName,
|
||||||
pub settings: std::sync::Arc<configs::Settings>,
|
|
||||||
pub subject: &'static str,
|
pub subject: &'static str,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -458,7 +457,6 @@ pub struct ProFeatureRequest {
|
|||||||
pub merchant_id: common_utils::id_type::MerchantId,
|
pub merchant_id: common_utils::id_type::MerchantId,
|
||||||
pub user_name: domain::UserName,
|
pub user_name: domain::UserName,
|
||||||
pub user_email: domain::UserEmail,
|
pub user_email: domain::UserEmail,
|
||||||
pub settings: std::sync::Arc<configs::Settings>,
|
|
||||||
pub subject: String,
|
pub subject: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user