mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-30 01:27:31 +08:00
feat(users): new routes to accept invite and list merchants (#4591)
This commit is contained in:
@ -7,7 +7,7 @@ use crate::user_role::{
|
|||||||
UpdateRoleRequest,
|
UpdateRoleRequest,
|
||||||
},
|
},
|
||||||
AcceptInvitationRequest, AuthorizationInfoResponse, DeleteUserRoleRequest,
|
AcceptInvitationRequest, AuthorizationInfoResponse, DeleteUserRoleRequest,
|
||||||
TransferOrgOwnershipRequest, UpdateUserRoleRequest,
|
MerchantSelectRequest, TransferOrgOwnershipRequest, UpdateUserRoleRequest,
|
||||||
};
|
};
|
||||||
|
|
||||||
common_utils::impl_misc_api_event_type!(
|
common_utils::impl_misc_api_event_type!(
|
||||||
@ -15,6 +15,7 @@ common_utils::impl_misc_api_event_type!(
|
|||||||
GetRoleRequest,
|
GetRoleRequest,
|
||||||
AuthorizationInfoResponse,
|
AuthorizationInfoResponse,
|
||||||
UpdateUserRoleRequest,
|
UpdateUserRoleRequest,
|
||||||
|
MerchantSelectRequest,
|
||||||
AcceptInvitationRequest,
|
AcceptInvitationRequest,
|
||||||
DeleteUserRoleRequest,
|
DeleteUserRoleRequest,
|
||||||
TransferOrgOwnershipRequest,
|
TransferOrgOwnershipRequest,
|
||||||
|
|||||||
@ -97,11 +97,15 @@ pub enum UserStatus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, serde::Deserialize, serde::Serialize)]
|
#[derive(Debug, serde::Deserialize, serde::Serialize)]
|
||||||
pub struct AcceptInvitationRequest {
|
pub struct MerchantSelectRequest {
|
||||||
pub merchant_ids: Vec<String>,
|
pub merchant_ids: Vec<String>,
|
||||||
// TODO: Remove this once the token only api is being used
|
// TODO: Remove this once the token only api is being used
|
||||||
pub need_dashboard_entry_response: Option<bool>,
|
pub need_dashboard_entry_response: Option<bool>,
|
||||||
}
|
}
|
||||||
|
#[derive(Debug, serde::Deserialize, serde::Serialize)]
|
||||||
|
pub struct AcceptInvitationRequest {
|
||||||
|
pub merchant_ids: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, serde::Deserialize, serde::Serialize)]
|
#[derive(Debug, serde::Deserialize, serde::Serialize)]
|
||||||
pub struct DeleteUserRoleRequest {
|
pub struct DeleteUserRoleRequest {
|
||||||
|
|||||||
@ -7,6 +7,8 @@ use diesel_models::{
|
|||||||
user_role::UserRoleNew,
|
user_role::UserRoleNew,
|
||||||
};
|
};
|
||||||
use error_stack::{report, ResultExt};
|
use error_stack::{report, ResultExt};
|
||||||
|
#[cfg(feature = "email")]
|
||||||
|
use external_services::email::EmailData;
|
||||||
use masking::{ExposeInterface, PeekInterface};
|
use masking::{ExposeInterface, PeekInterface};
|
||||||
#[cfg(feature = "email")]
|
#[cfg(feature = "email")]
|
||||||
use router_env::env;
|
use router_env::env;
|
||||||
@ -570,6 +572,7 @@ pub async fn invite_multiple_user(
|
|||||||
user_from_token: auth::UserFromToken,
|
user_from_token: auth::UserFromToken,
|
||||||
requests: Vec<user_api::InviteUserRequest>,
|
requests: Vec<user_api::InviteUserRequest>,
|
||||||
req_state: ReqState,
|
req_state: ReqState,
|
||||||
|
is_token_only: Option<bool>,
|
||||||
) -> UserResponse<Vec<InviteMultipleUserResponse>> {
|
) -> UserResponse<Vec<InviteMultipleUserResponse>> {
|
||||||
if requests.len() > 10 {
|
if requests.len() > 10 {
|
||||||
return Err(report!(UserErrors::MaxInvitationsError))
|
return Err(report!(UserErrors::MaxInvitationsError))
|
||||||
@ -577,7 +580,8 @@ pub async fn invite_multiple_user(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let responses = futures::future::join_all(requests.iter().map(|request| async {
|
let responses = futures::future::join_all(requests.iter().map(|request| async {
|
||||||
match handle_invitation(&state, &user_from_token, request, &req_state).await {
|
match handle_invitation(&state, &user_from_token, request, &req_state, is_token_only).await
|
||||||
|
{
|
||||||
Ok(response) => response,
|
Ok(response) => response,
|
||||||
Err(error) => InviteMultipleUserResponse {
|
Err(error) => InviteMultipleUserResponse {
|
||||||
email: request.email.clone(),
|
email: request.email.clone(),
|
||||||
@ -597,6 +601,7 @@ async fn handle_invitation(
|
|||||||
user_from_token: &auth::UserFromToken,
|
user_from_token: &auth::UserFromToken,
|
||||||
request: &user_api::InviteUserRequest,
|
request: &user_api::InviteUserRequest,
|
||||||
req_state: &ReqState,
|
req_state: &ReqState,
|
||||||
|
is_token_only: Option<bool>,
|
||||||
) -> UserResult<InviteMultipleUserResponse> {
|
) -> UserResult<InviteMultipleUserResponse> {
|
||||||
let inviter_user = user_from_token.get_user_from_db(state).await?;
|
let inviter_user = user_from_token.get_user_from_db(state).await?;
|
||||||
|
|
||||||
@ -635,7 +640,14 @@ async fn handle_invitation(
|
|||||||
.err()
|
.err()
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
{
|
{
|
||||||
handle_new_user_invitation(state, user_from_token, request, req_state.clone()).await
|
handle_new_user_invitation(
|
||||||
|
state,
|
||||||
|
user_from_token,
|
||||||
|
request,
|
||||||
|
req_state.clone(),
|
||||||
|
is_token_only,
|
||||||
|
)
|
||||||
|
.await
|
||||||
} else {
|
} else {
|
||||||
Err(UserErrors::InternalServerError.into())
|
Err(UserErrors::InternalServerError.into())
|
||||||
}
|
}
|
||||||
@ -718,6 +730,7 @@ async fn handle_new_user_invitation(
|
|||||||
user_from_token: &auth::UserFromToken,
|
user_from_token: &auth::UserFromToken,
|
||||||
request: &user_api::InviteUserRequest,
|
request: &user_api::InviteUserRequest,
|
||||||
req_state: ReqState,
|
req_state: ReqState,
|
||||||
|
is_token_only: Option<bool>,
|
||||||
) -> UserResult<InviteMultipleUserResponse> {
|
) -> UserResult<InviteMultipleUserResponse> {
|
||||||
let new_user = domain::NewUser::try_from((request.clone(), user_from_token.clone()))?;
|
let new_user = domain::NewUser::try_from((request.clone(), user_from_token.clone()))?;
|
||||||
|
|
||||||
@ -756,25 +769,36 @@ async fn handle_new_user_invitation(
|
|||||||
})?;
|
})?;
|
||||||
|
|
||||||
let is_email_sent;
|
let is_email_sent;
|
||||||
|
// TODO: Adding this to avoid clippy lints, remove this once the token only flow is being used
|
||||||
|
let _ = is_token_only;
|
||||||
|
|
||||||
#[cfg(feature = "email")]
|
#[cfg(feature = "email")]
|
||||||
{
|
{
|
||||||
// TODO: Adding this to avoid clippy lints
|
// TODO: Adding this to avoid clippy lints
|
||||||
// Will be adding actual usage for this variable later
|
// Will be adding actual usage for this variable later
|
||||||
let _ = req_state.clone();
|
let _ = req_state.clone();
|
||||||
let invitee_email = domain::UserEmail::from_pii_email(request.email.clone())?;
|
let invitee_email = domain::UserEmail::from_pii_email(request.email.clone())?;
|
||||||
let email_contents = email_types::InviteUser {
|
let email_contents: Box<dyn EmailData + Send + 'static> = if let Some(true) = is_token_only
|
||||||
recipient_email: invitee_email,
|
{
|
||||||
user_name: domain::UserName::new(new_user.get_name())?,
|
Box::new(email_types::InviteRegisteredUser {
|
||||||
settings: state.conf.clone(),
|
recipient_email: invitee_email,
|
||||||
subject: "You have been invited to join Hyperswitch Community!",
|
user_name: domain::UserName::new(new_user.get_name())?,
|
||||||
merchant_id: user_from_token.merchant_id.clone(),
|
settings: state.conf.clone(),
|
||||||
|
subject: "You have been invited to join Hyperswitch Community!",
|
||||||
|
merchant_id: user_from_token.merchant_id.clone(),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Box::new(email_types::InviteUser {
|
||||||
|
recipient_email: invitee_email,
|
||||||
|
user_name: domain::UserName::new(new_user.get_name())?,
|
||||||
|
settings: state.conf.clone(),
|
||||||
|
subject: "You have been invited to join Hyperswitch Community!",
|
||||||
|
merchant_id: user_from_token.merchant_id.clone(),
|
||||||
|
})
|
||||||
};
|
};
|
||||||
let send_email_result = state
|
let send_email_result = state
|
||||||
.email_client
|
.email_client
|
||||||
.compose_and_send_email(
|
.compose_and_send_email(email_contents, state.conf.proxy.https_url.as_ref())
|
||||||
Box::new(email_contents),
|
|
||||||
state.conf.proxy.https_url.as_ref(),
|
|
||||||
)
|
|
||||||
.await;
|
.await;
|
||||||
logger::info!(?send_email_result);
|
logger::info!(?send_email_result);
|
||||||
is_email_sent = send_email_result.is_ok();
|
is_email_sent = send_email_result.is_ok();
|
||||||
@ -1203,11 +1227,11 @@ pub async fn create_merchant_account(
|
|||||||
|
|
||||||
pub async fn list_merchants_for_user(
|
pub async fn list_merchants_for_user(
|
||||||
state: AppState,
|
state: AppState,
|
||||||
user_from_token: auth::UserFromToken,
|
user_from_token: Box<dyn auth::GetUserIdFromAuth>,
|
||||||
) -> UserResponse<Vec<user_api::UserMerchantAccount>> {
|
) -> UserResponse<Vec<user_api::UserMerchantAccount>> {
|
||||||
let user_roles = state
|
let user_roles = state
|
||||||
.store
|
.store
|
||||||
.list_user_roles_by_user_id(user_from_token.user_id.as_str())
|
.list_user_roles_by_user_id(user_from_token.get_user_id().as_str())
|
||||||
.await
|
.await
|
||||||
.change_context(UserErrors::InternalServerError)?;
|
.change_context(UserErrors::InternalServerError)?;
|
||||||
|
|
||||||
|
|||||||
@ -170,8 +170,38 @@ pub async fn transfer_org_ownership(
|
|||||||
|
|
||||||
pub async fn accept_invitation(
|
pub async fn accept_invitation(
|
||||||
state: AppState,
|
state: AppState,
|
||||||
user_token: auth::UserFromSinglePurposeToken,
|
user_token: auth::UserFromToken,
|
||||||
req: user_role_api::AcceptInvitationRequest,
|
req: user_role_api::AcceptInvitationRequest,
|
||||||
|
) -> UserResponse<()> {
|
||||||
|
futures::future::join_all(req.merchant_ids.iter().map(|merchant_id| async {
|
||||||
|
state
|
||||||
|
.store
|
||||||
|
.update_user_role_by_user_id_merchant_id(
|
||||||
|
user_token.user_id.as_str(),
|
||||||
|
merchant_id,
|
||||||
|
UserRoleUpdate::UpdateStatus {
|
||||||
|
status: UserStatus::Active,
|
||||||
|
modified_by: user_token.user_id.clone(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(|e| {
|
||||||
|
logger::error!("Error while accepting invitation {}", e);
|
||||||
|
})
|
||||||
|
.ok()
|
||||||
|
}))
|
||||||
|
.await
|
||||||
|
.into_iter()
|
||||||
|
.reduce(Option::or)
|
||||||
|
.flatten()
|
||||||
|
.ok_or(UserErrors::MerchantIdNotFound.into())
|
||||||
|
.map(|_| ApplicationResponse::StatusOk)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn merchant_select(
|
||||||
|
state: AppState,
|
||||||
|
user_token: auth::UserFromSinglePurposeToken,
|
||||||
|
req: user_role_api::MerchantSelectRequest,
|
||||||
) -> UserResponse<user_api::TokenOrPayloadResponse<user_api::DashboardEntryResponse>> {
|
) -> UserResponse<user_api::TokenOrPayloadResponse<user_api::DashboardEntryResponse>> {
|
||||||
let user_role = futures::future::join_all(req.merchant_ids.iter().map(|merchant_id| async {
|
let user_role = futures::future::join_all(req.merchant_ids.iter().map(|merchant_id| async {
|
||||||
state
|
state
|
||||||
@ -207,7 +237,6 @@ pub async fn accept_invitation(
|
|||||||
utils::user_role::set_role_permissions_in_cache_by_user_role(&state, &user_role).await;
|
utils::user_role::set_role_permissions_in_cache_by_user_role(&state, &user_role).await;
|
||||||
|
|
||||||
let token = utils::user::generate_jwt_auth_token(&state, &user_from_db, &user_role).await?;
|
let token = utils::user::generate_jwt_auth_token(&state, &user_from_db, &user_role).await?;
|
||||||
|
|
||||||
let response = utils::user::get_dashboard_entry_response(
|
let response = utils::user::get_dashboard_entry_response(
|
||||||
&state,
|
&state,
|
||||||
user_from_db,
|
user_from_db,
|
||||||
@ -223,10 +252,10 @@ pub async fn accept_invitation(
|
|||||||
Ok(ApplicationResponse::StatusOk)
|
Ok(ApplicationResponse::StatusOk)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn accept_invitation_token_only_flow(
|
pub async fn merchant_select_token_only_flow(
|
||||||
state: AppState,
|
state: AppState,
|
||||||
user_token: auth::UserFromSinglePurposeToken,
|
user_token: auth::UserFromSinglePurposeToken,
|
||||||
req: user_role_api::AcceptInvitationRequest,
|
req: user_role_api::MerchantSelectRequest,
|
||||||
) -> UserResponse<user_api::TokenOrPayloadResponse<user_api::DashboardEntryResponse>> {
|
) -> UserResponse<user_api::TokenOrPayloadResponse<user_api::DashboardEntryResponse>> {
|
||||||
let user_role = futures::future::join_all(req.merchant_ids.iter().map(|merchant_id| async {
|
let user_role = futures::future::join_all(req.merchant_ids.iter().map(|merchant_id| async {
|
||||||
state
|
state
|
||||||
|
|||||||
@ -1192,6 +1192,11 @@ impl User {
|
|||||||
// TODO: Remove this endpoint once migration to /merchants/list is done
|
// TODO: Remove this endpoint once migration to /merchants/list is done
|
||||||
.service(web::resource("/switch/list").route(web::get().to(list_merchants_for_user)))
|
.service(web::resource("/switch/list").route(web::get().to(list_merchants_for_user)))
|
||||||
.service(web::resource("/merchants/list").route(web::get().to(list_merchants_for_user)))
|
.service(web::resource("/merchants/list").route(web::get().to(list_merchants_for_user)))
|
||||||
|
// The route is utilized to select an invitation from a list of merchants in an intermediate state
|
||||||
|
.service(
|
||||||
|
web::resource("/merchants_select/list")
|
||||||
|
.route(web::get().to(list_merchants_for_user_with_spt)),
|
||||||
|
)
|
||||||
.service(web::resource("/permission_info").route(web::get().to(get_authorization_info)))
|
.service(web::resource("/permission_info").route(web::get().to(get_authorization_info)))
|
||||||
.service(web::resource("/update").route(web::post().to(update_user_account_details)))
|
.service(web::resource("/update").route(web::post().to(update_user_account_details)))
|
||||||
.service(
|
.service(
|
||||||
@ -1241,7 +1246,11 @@ impl User {
|
|||||||
.service(
|
.service(
|
||||||
web::resource("/invite_multiple").route(web::post().to(invite_multiple_user)),
|
web::resource("/invite_multiple").route(web::post().to(invite_multiple_user)),
|
||||||
)
|
)
|
||||||
.service(web::resource("/invite/accept").route(web::post().to(accept_invitation)))
|
.service(
|
||||||
|
web::resource("/invite/accept")
|
||||||
|
.route(web::post().to(merchant_select))
|
||||||
|
.route(web::put().to(accept_invitation)),
|
||||||
|
)
|
||||||
.service(web::resource("/update_role").route(web::post().to(update_user_role)))
|
.service(web::resource("/update_role").route(web::post().to(update_user_role)))
|
||||||
.service(
|
.service(
|
||||||
web::resource("/transfer_ownership")
|
web::resource("/transfer_ownership")
|
||||||
|
|||||||
@ -220,6 +220,7 @@ impl From<Flow> for ApiIdentifier {
|
|||||||
| Flow::UpdateUserRole
|
| Flow::UpdateUserRole
|
||||||
| Flow::GetAuthorizationInfo
|
| Flow::GetAuthorizationInfo
|
||||||
| Flow::AcceptInvitation
|
| Flow::AcceptInvitation
|
||||||
|
| Flow::MerchantSelect
|
||||||
| Flow::DeleteUserRole
|
| Flow::DeleteUserRole
|
||||||
| Flow::TransferOrgOwnership
|
| Flow::TransferOrgOwnership
|
||||||
| Flow::CreateRole
|
| Flow::CreateRole
|
||||||
|
|||||||
@ -324,6 +324,23 @@ pub async fn list_merchants_for_user(state: web::Data<AppState>, req: HttpReques
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn list_merchants_for_user_with_spt(
|
||||||
|
state: web::Data<AppState>,
|
||||||
|
req: HttpRequest,
|
||||||
|
) -> HttpResponse {
|
||||||
|
let flow = Flow::UserMerchantAccountList;
|
||||||
|
Box::pin(api::server_wrap(
|
||||||
|
flow,
|
||||||
|
state,
|
||||||
|
&req,
|
||||||
|
(),
|
||||||
|
|state, user, _, _| user_core::list_merchants_for_user(state, user),
|
||||||
|
&auth::SinglePurposeJWTAuth(TokenPurpose::AcceptInvite),
|
||||||
|
api_locking::LockAction::NotApplicable,
|
||||||
|
))
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn get_user_role_details(
|
pub async fn get_user_role_details(
|
||||||
state: web::Data<AppState>,
|
state: web::Data<AppState>,
|
||||||
req: HttpRequest,
|
req: HttpRequest,
|
||||||
@ -435,14 +452,18 @@ pub async fn invite_multiple_user(
|
|||||||
state: web::Data<AppState>,
|
state: web::Data<AppState>,
|
||||||
req: HttpRequest,
|
req: HttpRequest,
|
||||||
payload: web::Json<Vec<user_api::InviteUserRequest>>,
|
payload: web::Json<Vec<user_api::InviteUserRequest>>,
|
||||||
|
query: web::Query<user_api::TokenOnlyQueryParam>,
|
||||||
) -> HttpResponse {
|
) -> HttpResponse {
|
||||||
let flow = Flow::InviteMultipleUser;
|
let flow = Flow::InviteMultipleUser;
|
||||||
|
let is_token_only = query.into_inner().token_only;
|
||||||
Box::pin(api::server_wrap(
|
Box::pin(api::server_wrap(
|
||||||
flow,
|
flow,
|
||||||
state.clone(),
|
state.clone(),
|
||||||
&req,
|
&req,
|
||||||
payload.into_inner(),
|
payload.into_inner(),
|
||||||
user_core::invite_multiple_user,
|
|state, user, payload, req_state| {
|
||||||
|
user_core::invite_multiple_user(state, user, payload, req_state, is_token_only)
|
||||||
|
},
|
||||||
&auth::JWTAuth(Permission::UsersWrite),
|
&auth::JWTAuth(Permission::UsersWrite),
|
||||||
api_locking::LockAction::NotApplicable,
|
api_locking::LockAction::NotApplicable,
|
||||||
))
|
))
|
||||||
|
|||||||
@ -209,10 +209,29 @@ pub async fn accept_invitation(
|
|||||||
state: web::Data<AppState>,
|
state: web::Data<AppState>,
|
||||||
req: HttpRequest,
|
req: HttpRequest,
|
||||||
json_payload: web::Json<user_role_api::AcceptInvitationRequest>,
|
json_payload: web::Json<user_role_api::AcceptInvitationRequest>,
|
||||||
query: web::Query<user_api::TokenOnlyQueryParam>,
|
|
||||||
) -> HttpResponse {
|
) -> HttpResponse {
|
||||||
let flow = Flow::AcceptInvitation;
|
let flow = Flow::AcceptInvitation;
|
||||||
let payload = json_payload.into_inner();
|
let payload = json_payload.into_inner();
|
||||||
|
Box::pin(api::server_wrap(
|
||||||
|
flow,
|
||||||
|
state.clone(),
|
||||||
|
&req,
|
||||||
|
payload,
|
||||||
|
|state, user, req_body, _| user_role_core::accept_invitation(state, user, req_body),
|
||||||
|
&auth::DashboardNoPermissionAuth,
|
||||||
|
api_locking::LockAction::NotApplicable,
|
||||||
|
))
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn merchant_select(
|
||||||
|
state: web::Data<AppState>,
|
||||||
|
req: HttpRequest,
|
||||||
|
json_payload: web::Json<user_role_api::MerchantSelectRequest>,
|
||||||
|
query: web::Query<user_api::TokenOnlyQueryParam>,
|
||||||
|
) -> HttpResponse {
|
||||||
|
let flow = Flow::MerchantSelect;
|
||||||
|
let payload = json_payload.into_inner();
|
||||||
let is_token_only = query.into_inner().token_only;
|
let is_token_only = query.into_inner().token_only;
|
||||||
Box::pin(api::server_wrap(
|
Box::pin(api::server_wrap(
|
||||||
flow,
|
flow,
|
||||||
@ -221,9 +240,9 @@ pub async fn accept_invitation(
|
|||||||
payload,
|
payload,
|
||||||
|state, user, req_body, _| async move {
|
|state, user, req_body, _| async move {
|
||||||
if let Some(true) = is_token_only {
|
if let Some(true) = is_token_only {
|
||||||
user_role_core::accept_invitation_token_only_flow(state, user, req_body).await
|
user_role_core::merchant_select_token_only_flow(state, user, req_body).await
|
||||||
} else {
|
} else {
|
||||||
user_role_core::accept_invitation(state, user, req_body).await
|
user_role_core::merchant_select(state, user, req_body).await
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
&auth::SinglePurposeJWTAuth(TokenPurpose::AcceptInvite),
|
&auth::SinglePurposeJWTAuth(TokenPurpose::AcceptInvite),
|
||||||
|
|||||||
@ -206,6 +206,23 @@ impl AuthInfo for AuthenticationData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait GetUserIdFromAuth {
|
||||||
|
fn get_user_id(&self) -> String;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GetUserIdFromAuth for UserFromToken {
|
||||||
|
fn get_user_id(&self) -> String {
|
||||||
|
self.user_id.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "olap")]
|
||||||
|
impl GetUserIdFromAuth for UserFromSinglePurposeToken {
|
||||||
|
fn get_user_id(&self) -> String {
|
||||||
|
self.user_id.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait AuthenticateAndFetch<T, A>
|
pub trait AuthenticateAndFetch<T, A>
|
||||||
where
|
where
|
||||||
@ -347,6 +364,39 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "olap")]
|
||||||
|
#[async_trait]
|
||||||
|
impl<A> AuthenticateAndFetch<Box<dyn GetUserIdFromAuth>, A> for SinglePurposeJWTAuth
|
||||||
|
where
|
||||||
|
A: AppStateInfo + Sync,
|
||||||
|
{
|
||||||
|
async fn authenticate_and_fetch(
|
||||||
|
&self,
|
||||||
|
request_headers: &HeaderMap,
|
||||||
|
state: &A,
|
||||||
|
) -> RouterResult<(Box<dyn GetUserIdFromAuth>, AuthenticationType)> {
|
||||||
|
let payload = parse_jwt_payload::<A, SinglePurposeToken>(request_headers, state).await?;
|
||||||
|
if payload.check_in_blacklist(state).await? {
|
||||||
|
return Err(errors::ApiErrorResponse::InvalidJwtToken.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.0 != payload.purpose {
|
||||||
|
return Err(errors::ApiErrorResponse::InvalidJwtToken.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok((
|
||||||
|
Box::new(UserFromSinglePurposeToken {
|
||||||
|
user_id: payload.user_id.clone(),
|
||||||
|
origin: payload.origin.clone(),
|
||||||
|
}),
|
||||||
|
AuthenticationType::SinglePurposeJWT {
|
||||||
|
user_id: payload.user_id,
|
||||||
|
purpose: payload.purpose,
|
||||||
|
},
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct AdminApiAuth;
|
pub struct AdminApiAuth;
|
||||||
|
|
||||||
@ -786,6 +836,37 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "olap")]
|
||||||
|
#[async_trait]
|
||||||
|
impl<A> AuthenticateAndFetch<Box<dyn GetUserIdFromAuth>, A> for DashboardNoPermissionAuth
|
||||||
|
where
|
||||||
|
A: AppStateInfo + Sync,
|
||||||
|
{
|
||||||
|
async fn authenticate_and_fetch(
|
||||||
|
&self,
|
||||||
|
request_headers: &HeaderMap,
|
||||||
|
state: &A,
|
||||||
|
) -> RouterResult<(Box<dyn GetUserIdFromAuth>, 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());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok((
|
||||||
|
Box::new(UserFromToken {
|
||||||
|
user_id: payload.user_id.clone(),
|
||||||
|
merchant_id: payload.merchant_id.clone(),
|
||||||
|
org_id: payload.org_id,
|
||||||
|
role_id: payload.role_id,
|
||||||
|
}),
|
||||||
|
AuthenticationType::MerchantJwt {
|
||||||
|
merchant_id: payload.merchant_id,
|
||||||
|
user_id: Some(payload.user_id),
|
||||||
|
},
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "olap")]
|
#[cfg(feature = "olap")]
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl<A> AuthenticateAndFetch<(), A> for DashboardNoPermissionAuth
|
impl<A> AuthenticateAndFetch<(), A> for DashboardNoPermissionAuth
|
||||||
|
|||||||
@ -386,6 +386,8 @@ pub enum Flow {
|
|||||||
UpdateUserAccountDetails,
|
UpdateUserAccountDetails,
|
||||||
/// Accept user invitation
|
/// Accept user invitation
|
||||||
AcceptInvitation,
|
AcceptInvitation,
|
||||||
|
/// Select merchant from invitations
|
||||||
|
MerchantSelect,
|
||||||
/// Initiate external authentication for a payment
|
/// Initiate external authentication for a payment
|
||||||
PaymentsExternalAuthentication,
|
PaymentsExternalAuthentication,
|
||||||
/// Authorize the payment after external 3ds authentication
|
/// Authorize the payment after external 3ds authentication
|
||||||
|
|||||||
Reference in New Issue
Block a user