mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-30 01:27:31 +08:00
feat(email): Add auth_id in email types and send auth_id in email URLs (#5120)
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
@ -346,7 +346,6 @@ wildcard_origin = false # If true, allows any origin to make req
|
|||||||
[email]
|
[email]
|
||||||
sender_email = "example@example.com" # Sender email
|
sender_email = "example@example.com" # Sender email
|
||||||
aws_region = "" # AWS region used by AWS SES
|
aws_region = "" # AWS region used by AWS SES
|
||||||
base_url = "" # Base url used when adding links that should redirect to self
|
|
||||||
allowed_unverified_days = 1 # Number of days the api calls ( with jwt token ) can be made without verifying the email
|
allowed_unverified_days = 1 # Number of days the api calls ( with jwt token ) can be made without verifying the email
|
||||||
active_email_client = "SES" # The currently active email client
|
active_email_client = "SES" # The currently active email client
|
||||||
|
|
||||||
@ -359,6 +358,7 @@ sts_role_session_name = "" # An identifier for the assumed role session, used to
|
|||||||
password_validity_in_days = 90 # Number of days after which password should be updated
|
password_validity_in_days = 90 # Number of days after which password should be updated
|
||||||
two_factor_auth_expiry_in_secs = 300 # Number of seconds after which 2FA should be done again if doing update/change from inside
|
two_factor_auth_expiry_in_secs = 300 # Number of seconds after which 2FA should be done again if doing update/change from inside
|
||||||
totp_issuer_name = "Hyperswitch" # Name of the issuer for TOTP
|
totp_issuer_name = "Hyperswitch" # Name of the issuer for TOTP
|
||||||
|
base_url = "" # Base url used for user specific redirects and emails
|
||||||
|
|
||||||
#tokenization configuration which describe token lifetime and payment method for specific connector
|
#tokenization configuration which describe token lifetime and payment method for specific connector
|
||||||
[tokenization]
|
[tokenization]
|
||||||
|
|||||||
@ -58,7 +58,6 @@ wildcard_origin = false # If true, allows any origin to make req
|
|||||||
[email]
|
[email]
|
||||||
sender_email = "example@example.com" # Sender email
|
sender_email = "example@example.com" # Sender email
|
||||||
aws_region = "" # AWS region used by AWS SES
|
aws_region = "" # AWS region used by AWS SES
|
||||||
base_url = "" # Dashboard base url used when adding links that should redirect to self, say https://app.hyperswitch.io for example
|
|
||||||
allowed_unverified_days = 1 # Number of days the api calls ( with jwt token ) can be made without verifying the email
|
allowed_unverified_days = 1 # Number of days the api calls ( with jwt token ) can be made without verifying the email
|
||||||
active_email_client = "SES" # The currently active email client
|
active_email_client = "SES" # The currently active email client
|
||||||
|
|
||||||
|
|||||||
@ -118,6 +118,7 @@ slack_invite_url = "https://join.slack.com/t/hyperswitch-io/shared_invite/zt-2aw
|
|||||||
password_validity_in_days = 90
|
password_validity_in_days = 90
|
||||||
two_factor_auth_expiry_in_secs = 300
|
two_factor_auth_expiry_in_secs = 300
|
||||||
totp_issuer_name = "Hyperswitch Integ"
|
totp_issuer_name = "Hyperswitch Integ"
|
||||||
|
base_url = "https://integ.hyperswitch.io"
|
||||||
|
|
||||||
[frm]
|
[frm]
|
||||||
enabled = true
|
enabled = true
|
||||||
|
|||||||
@ -125,6 +125,7 @@ slack_invite_url = "https://join.slack.com/t/hyperswitch-io/shared_invite/zt-2aw
|
|||||||
password_validity_in_days = 90
|
password_validity_in_days = 90
|
||||||
two_factor_auth_expiry_in_secs = 300
|
two_factor_auth_expiry_in_secs = 300
|
||||||
totp_issuer_name = "Hyperswitch Production"
|
totp_issuer_name = "Hyperswitch Production"
|
||||||
|
base_url = "https://live.hyperswitch.io"
|
||||||
|
|
||||||
[frm]
|
[frm]
|
||||||
enabled = false
|
enabled = false
|
||||||
|
|||||||
@ -125,6 +125,7 @@ slack_invite_url = "https://join.slack.com/t/hyperswitch-io/shared_invite/zt-2aw
|
|||||||
password_validity_in_days = 90
|
password_validity_in_days = 90
|
||||||
two_factor_auth_expiry_in_secs = 300
|
two_factor_auth_expiry_in_secs = 300
|
||||||
totp_issuer_name = "Hyperswitch Sandbox"
|
totp_issuer_name = "Hyperswitch Sandbox"
|
||||||
|
base_url = "https://app.hyperswitch.io"
|
||||||
|
|
||||||
[frm]
|
[frm]
|
||||||
enabled = true
|
enabled = true
|
||||||
|
|||||||
@ -264,7 +264,6 @@ wildcard_origin = true
|
|||||||
[email]
|
[email]
|
||||||
sender_email = "example@example.com"
|
sender_email = "example@example.com"
|
||||||
aws_region = ""
|
aws_region = ""
|
||||||
base_url = "http://localhost:8080"
|
|
||||||
allowed_unverified_days = 1
|
allowed_unverified_days = 1
|
||||||
active_email_client = "SES"
|
active_email_client = "SES"
|
||||||
|
|
||||||
@ -276,6 +275,7 @@ sts_role_session_name = ""
|
|||||||
password_validity_in_days = 90
|
password_validity_in_days = 90
|
||||||
two_factor_auth_expiry_in_secs = 300
|
two_factor_auth_expiry_in_secs = 300
|
||||||
totp_issuer_name = "Hyperswitch Dev"
|
totp_issuer_name = "Hyperswitch Dev"
|
||||||
|
base_url = "http://localhost:8080"
|
||||||
|
|
||||||
[bank_config.eps]
|
[bank_config.eps]
|
||||||
stripe = { banks = "arzte_und_apotheker_bank,austrian_anadi_bank_ag,bank_austria,bankhaus_carl_spangler,bankhaus_schelhammer_und_schattera_ag,bawag_psk_ag,bks_bank_ag,brull_kallmus_bank_ag,btv_vier_lander_bank,capital_bank_grawe_gruppe_ag,dolomitenbank,easybank_ag,erste_bank_und_sparkassen,hypo_alpeadriabank_international_ag,hypo_noe_lb_fur_niederosterreich_u_wien,hypo_oberosterreich_salzburg_steiermark,hypo_tirol_bank_ag,hypo_vorarlberg_bank_ag,hypo_bank_burgenland_aktiengesellschaft,marchfelder_bank,oberbank_ag,raiffeisen_bankengruppe_osterreich,schoellerbank_ag,sparda_bank_wien,volksbank_gruppe,volkskreditbank_ag,vr_bank_braunau" }
|
stripe = { banks = "arzte_und_apotheker_bank,austrian_anadi_bank_ag,bank_austria,bankhaus_carl_spangler,bankhaus_schelhammer_und_schattera_ag,bawag_psk_ag,bks_bank_ag,brull_kallmus_bank_ag,btv_vier_lander_bank,capital_bank_grawe_gruppe_ag,dolomitenbank,easybank_ag,erste_bank_und_sparkassen,hypo_alpeadriabank_international_ag,hypo_noe_lb_fur_niederosterreich_u_wien,hypo_oberosterreich_salzburg_steiermark,hypo_tirol_bank_ag,hypo_vorarlberg_bank_ag,hypo_bank_burgenland_aktiengesellschaft,marchfelder_bank,oberbank_ag,raiffeisen_bankengruppe_osterreich,schoellerbank_ag,sparda_bank_wien,volksbank_gruppe,volkskreditbank_ag,vr_bank_braunau" }
|
||||||
|
|||||||
@ -56,6 +56,7 @@ recon_admin_api_key = "recon_test_admin"
|
|||||||
password_validity_in_days = 90
|
password_validity_in_days = 90
|
||||||
two_factor_auth_expiry_in_secs = 300
|
two_factor_auth_expiry_in_secs = 300
|
||||||
totp_issuer_name = "Hyperswitch"
|
totp_issuer_name = "Hyperswitch"
|
||||||
|
base_url = "http://localhost:8080"
|
||||||
|
|
||||||
[locker]
|
[locker]
|
||||||
host = ""
|
host = ""
|
||||||
|
|||||||
@ -355,3 +355,8 @@ pub struct AuthMethodDetails {
|
|||||||
pub auth_type: common_enums::UserAuthType,
|
pub auth_type: common_enums::UserAuthType,
|
||||||
pub name: Option<OpenIdProvider>,
|
pub name: Option<OpenIdProvider>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, serde::Deserialize, serde::Serialize)]
|
||||||
|
pub struct AuthIdQueryParam {
|
||||||
|
pub auth_id: Option<String>,
|
||||||
|
}
|
||||||
|
|||||||
@ -126,9 +126,6 @@ pub struct EmailSettings {
|
|||||||
/// The AWS region to send SES requests to.
|
/// The AWS region to send SES requests to.
|
||||||
pub aws_region: String,
|
pub aws_region: String,
|
||||||
|
|
||||||
/// Base-url used when adding links that should redirect to self
|
|
||||||
pub base_url: String,
|
|
||||||
|
|
||||||
/// Number of days for verification of the email
|
/// Number of days for verification of the email
|
||||||
pub allowed_unverified_days: i64,
|
pub allowed_unverified_days: i64,
|
||||||
|
|
||||||
|
|||||||
@ -484,6 +484,7 @@ pub struct UserSettings {
|
|||||||
pub password_validity_in_days: u16,
|
pub password_validity_in_days: u16,
|
||||||
pub two_factor_auth_expiry_in_secs: i64,
|
pub two_factor_auth_expiry_in_secs: i64,
|
||||||
pub totp_issuer_name: String,
|
pub totp_issuer_name: String,
|
||||||
|
pub base_url: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Clone)]
|
#[derive(Debug, Deserialize, Clone)]
|
||||||
|
|||||||
@ -39,6 +39,7 @@ pub mod sample_data;
|
|||||||
pub async fn signup_with_merchant_id(
|
pub async fn signup_with_merchant_id(
|
||||||
state: SessionState,
|
state: SessionState,
|
||||||
request: user_api::SignUpWithMerchantIdRequest,
|
request: user_api::SignUpWithMerchantIdRequest,
|
||||||
|
auth_id: Option<String>,
|
||||||
) -> UserResponse<user_api::SignUpWithMerchantIdResponse> {
|
) -> UserResponse<user_api::SignUpWithMerchantIdResponse> {
|
||||||
let new_user = domain::NewUser::try_from(request.clone())?;
|
let new_user = domain::NewUser::try_from(request.clone())?;
|
||||||
new_user
|
new_user
|
||||||
@ -64,6 +65,7 @@ pub async fn signup_with_merchant_id(
|
|||||||
user_name: domain::UserName::new(user_from_db.get_name())?,
|
user_name: domain::UserName::new(user_from_db.get_name())?,
|
||||||
settings: state.conf.clone(),
|
settings: state.conf.clone(),
|
||||||
subject: "Get back to Hyperswitch - Reset Your Password Now",
|
subject: "Get back to Hyperswitch - Reset Your Password Now",
|
||||||
|
auth_id,
|
||||||
};
|
};
|
||||||
|
|
||||||
let send_email_result = state
|
let send_email_result = state
|
||||||
@ -241,6 +243,7 @@ pub async fn signin_token_only_flow(
|
|||||||
pub async fn connect_account(
|
pub async fn connect_account(
|
||||||
state: SessionState,
|
state: SessionState,
|
||||||
request: user_api::ConnectAccountRequest,
|
request: user_api::ConnectAccountRequest,
|
||||||
|
auth_id: Option<String>,
|
||||||
) -> UserResponse<user_api::ConnectAccountResponse> {
|
) -> UserResponse<user_api::ConnectAccountResponse> {
|
||||||
let find_user = state.global_store.find_user_by_email(&request.email).await;
|
let find_user = state.global_store.find_user_by_email(&request.email).await;
|
||||||
|
|
||||||
@ -253,6 +256,7 @@ pub async fn connect_account(
|
|||||||
settings: state.conf.clone(),
|
settings: state.conf.clone(),
|
||||||
user_name: domain::UserName::new(user_from_db.get_name())?,
|
user_name: domain::UserName::new(user_from_db.get_name())?,
|
||||||
subject: "Unlock Hyperswitch: Use Your Magic Link to Sign In",
|
subject: "Unlock Hyperswitch: Use Your Magic Link to Sign In",
|
||||||
|
auth_id,
|
||||||
};
|
};
|
||||||
|
|
||||||
let send_email_result = state
|
let send_email_result = state
|
||||||
@ -303,6 +307,7 @@ pub async fn connect_account(
|
|||||||
recipient_email: domain::UserEmail::from_pii_email(user_from_db.get_email())?,
|
recipient_email: domain::UserEmail::from_pii_email(user_from_db.get_email())?,
|
||||||
settings: state.conf.clone(),
|
settings: state.conf.clone(),
|
||||||
subject: "Welcome to the Hyperswitch community!",
|
subject: "Welcome to the Hyperswitch community!",
|
||||||
|
auth_id,
|
||||||
};
|
};
|
||||||
|
|
||||||
let send_email_result = state
|
let send_email_result = state
|
||||||
@ -401,6 +406,7 @@ pub async fn change_password(
|
|||||||
pub async fn forgot_password(
|
pub async fn forgot_password(
|
||||||
state: SessionState,
|
state: SessionState,
|
||||||
request: user_api::ForgotPasswordRequest,
|
request: user_api::ForgotPasswordRequest,
|
||||||
|
auth_id: Option<String>,
|
||||||
) -> UserResponse<()> {
|
) -> UserResponse<()> {
|
||||||
let user_email = domain::UserEmail::from_pii_email(request.email)?;
|
let user_email = domain::UserEmail::from_pii_email(request.email)?;
|
||||||
|
|
||||||
@ -422,6 +428,7 @@ pub async fn forgot_password(
|
|||||||
settings: state.conf.clone(),
|
settings: state.conf.clone(),
|
||||||
user_name: domain::UserName::new(user_from_db.get_name())?,
|
user_name: domain::UserName::new(user_from_db.get_name())?,
|
||||||
subject: "Get back to Hyperswitch - Reset Your Password Now",
|
subject: "Get back to Hyperswitch - Reset Your Password Now",
|
||||||
|
auth_id,
|
||||||
};
|
};
|
||||||
|
|
||||||
state
|
state
|
||||||
@ -596,6 +603,7 @@ pub async fn invite_multiple_user(
|
|||||||
requests: Vec<user_api::InviteUserRequest>,
|
requests: Vec<user_api::InviteUserRequest>,
|
||||||
req_state: ReqState,
|
req_state: ReqState,
|
||||||
is_token_only: Option<bool>,
|
is_token_only: Option<bool>,
|
||||||
|
auth_id: Option<String>,
|
||||||
) -> UserResponse<Vec<InviteMultipleUserResponse>> {
|
) -> UserResponse<Vec<InviteMultipleUserResponse>> {
|
||||||
if requests.len() > 10 {
|
if requests.len() > 10 {
|
||||||
return Err(report!(UserErrors::MaxInvitationsError))
|
return Err(report!(UserErrors::MaxInvitationsError))
|
||||||
@ -603,7 +611,15 @@ 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, is_token_only).await
|
match handle_invitation(
|
||||||
|
&state,
|
||||||
|
&user_from_token,
|
||||||
|
request,
|
||||||
|
&req_state,
|
||||||
|
is_token_only,
|
||||||
|
&auth_id,
|
||||||
|
)
|
||||||
|
.await
|
||||||
{
|
{
|
||||||
Ok(response) => response,
|
Ok(response) => response,
|
||||||
Err(error) => InviteMultipleUserResponse {
|
Err(error) => InviteMultipleUserResponse {
|
||||||
@ -625,6 +641,7 @@ async fn handle_invitation(
|
|||||||
request: &user_api::InviteUserRequest,
|
request: &user_api::InviteUserRequest,
|
||||||
req_state: &ReqState,
|
req_state: &ReqState,
|
||||||
is_token_only: Option<bool>,
|
is_token_only: Option<bool>,
|
||||||
|
auth_id: &Option<String>,
|
||||||
) -> 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?;
|
||||||
|
|
||||||
@ -656,7 +673,14 @@ async fn handle_invitation(
|
|||||||
.await;
|
.await;
|
||||||
|
|
||||||
if let Ok(invitee_user) = invitee_user {
|
if let Ok(invitee_user) = invitee_user {
|
||||||
handle_existing_user_invitation(state, user_from_token, request, invitee_user.into()).await
|
handle_existing_user_invitation(
|
||||||
|
state,
|
||||||
|
user_from_token,
|
||||||
|
request,
|
||||||
|
invitee_user.into(),
|
||||||
|
auth_id,
|
||||||
|
)
|
||||||
|
.await
|
||||||
} else if invitee_user
|
} else if invitee_user
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map_err(|e| e.current_context().is_db_not_found())
|
.map_err(|e| e.current_context().is_db_not_found())
|
||||||
@ -669,6 +693,7 @@ async fn handle_invitation(
|
|||||||
request,
|
request,
|
||||||
req_state.clone(),
|
req_state.clone(),
|
||||||
is_token_only,
|
is_token_only,
|
||||||
|
auth_id,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
} else {
|
} else {
|
||||||
@ -676,12 +701,13 @@ async fn handle_invitation(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: send email
|
#[allow(unused_variables)]
|
||||||
async fn handle_existing_user_invitation(
|
async fn handle_existing_user_invitation(
|
||||||
state: &SessionState,
|
state: &SessionState,
|
||||||
user_from_token: &auth::UserFromToken,
|
user_from_token: &auth::UserFromToken,
|
||||||
request: &user_api::InviteUserRequest,
|
request: &user_api::InviteUserRequest,
|
||||||
invitee_user_from_db: domain::UserFromStorage,
|
invitee_user_from_db: domain::UserFromStorage,
|
||||||
|
auth_id: &Option<String>,
|
||||||
) -> UserResult<InviteMultipleUserResponse> {
|
) -> UserResult<InviteMultipleUserResponse> {
|
||||||
let now = common_utils::date_time::now();
|
let now = common_utils::date_time::now();
|
||||||
state
|
state
|
||||||
@ -722,6 +748,7 @@ async fn handle_existing_user_invitation(
|
|||||||
settings: state.conf.clone(),
|
settings: state.conf.clone(),
|
||||||
subject: "You have been invited to join Hyperswitch Community!",
|
subject: "You have been invited to join Hyperswitch Community!",
|
||||||
merchant_id: user_from_token.merchant_id.clone(),
|
merchant_id: user_from_token.merchant_id.clone(),
|
||||||
|
auth_id: auth_id.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
is_email_sent = state
|
is_email_sent = state
|
||||||
@ -748,12 +775,14 @@ async fn handle_existing_user_invitation(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused_variables)]
|
||||||
async fn handle_new_user_invitation(
|
async fn handle_new_user_invitation(
|
||||||
state: &SessionState,
|
state: &SessionState,
|
||||||
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>,
|
is_token_only: Option<bool>,
|
||||||
|
auth_id: &Option<String>,
|
||||||
) -> 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()))?;
|
||||||
|
|
||||||
@ -809,6 +838,7 @@ async fn handle_new_user_invitation(
|
|||||||
settings: state.conf.clone(),
|
settings: state.conf.clone(),
|
||||||
subject: "You have been invited to join Hyperswitch Community!",
|
subject: "You have been invited to join Hyperswitch Community!",
|
||||||
merchant_id: user_from_token.merchant_id.clone(),
|
merchant_id: user_from_token.merchant_id.clone(),
|
||||||
|
auth_id: auth_id.clone(),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
Box::new(email_types::InviteUser {
|
Box::new(email_types::InviteUser {
|
||||||
@ -817,6 +847,7 @@ async fn handle_new_user_invitation(
|
|||||||
settings: state.conf.clone(),
|
settings: state.conf.clone(),
|
||||||
subject: "You have been invited to join Hyperswitch Community!",
|
subject: "You have been invited to join Hyperswitch Community!",
|
||||||
merchant_id: user_from_token.merchant_id.clone(),
|
merchant_id: user_from_token.merchant_id.clone(),
|
||||||
|
auth_id: auth_id.clone(),
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
let send_email_result = state
|
let send_email_result = state
|
||||||
@ -862,7 +893,7 @@ pub async fn resend_invite(
|
|||||||
state: SessionState,
|
state: SessionState,
|
||||||
user_from_token: auth::UserFromToken,
|
user_from_token: auth::UserFromToken,
|
||||||
request: user_api::ReInviteUserRequest,
|
request: user_api::ReInviteUserRequest,
|
||||||
_req_state: ReqState,
|
auth_id: Option<String>,
|
||||||
) -> UserResponse<()> {
|
) -> UserResponse<()> {
|
||||||
let invitee_email = domain::UserEmail::from_pii_email(request.email)?;
|
let invitee_email = domain::UserEmail::from_pii_email(request.email)?;
|
||||||
let user: domain::UserFromStorage = state
|
let user: domain::UserFromStorage = state
|
||||||
@ -906,6 +937,7 @@ pub async fn resend_invite(
|
|||||||
settings: state.conf.clone(),
|
settings: state.conf.clone(),
|
||||||
subject: "You have been invited to join Hyperswitch Community!",
|
subject: "You have been invited to join Hyperswitch Community!",
|
||||||
merchant_id: user_from_token.merchant_id,
|
merchant_id: user_from_token.merchant_id,
|
||||||
|
auth_id,
|
||||||
};
|
};
|
||||||
state
|
state
|
||||||
.email_client
|
.email_client
|
||||||
@ -1518,6 +1550,7 @@ pub async fn verify_email_token_only_flow(
|
|||||||
pub async fn send_verification_mail(
|
pub async fn send_verification_mail(
|
||||||
state: SessionState,
|
state: SessionState,
|
||||||
req: user_api::SendVerifyEmailRequest,
|
req: user_api::SendVerifyEmailRequest,
|
||||||
|
auth_id: Option<String>,
|
||||||
) -> UserResponse<()> {
|
) -> UserResponse<()> {
|
||||||
let user_email = domain::UserEmail::try_from(req.email)?;
|
let user_email = domain::UserEmail::try_from(req.email)?;
|
||||||
let user = state
|
let user = state
|
||||||
@ -1540,6 +1573,7 @@ pub async fn send_verification_mail(
|
|||||||
recipient_email: domain::UserEmail::from_pii_email(user.email)?,
|
recipient_email: domain::UserEmail::from_pii_email(user.email)?,
|
||||||
settings: state.conf.clone(),
|
settings: state.conf.clone(),
|
||||||
subject: "Welcome to the Hyperswitch community!",
|
subject: "Welcome to the Hyperswitch community!",
|
||||||
|
auth_id,
|
||||||
};
|
};
|
||||||
|
|
||||||
state
|
state
|
||||||
|
|||||||
@ -39,15 +39,19 @@ pub async fn user_signup_with_merchant_id(
|
|||||||
state: web::Data<AppState>,
|
state: web::Data<AppState>,
|
||||||
http_req: HttpRequest,
|
http_req: HttpRequest,
|
||||||
json_payload: web::Json<user_api::SignUpWithMerchantIdRequest>,
|
json_payload: web::Json<user_api::SignUpWithMerchantIdRequest>,
|
||||||
|
query: web::Query<user_api::AuthIdQueryParam>,
|
||||||
) -> HttpResponse {
|
) -> HttpResponse {
|
||||||
let flow = Flow::UserSignUpWithMerchantId;
|
let flow = Flow::UserSignUpWithMerchantId;
|
||||||
let req_payload = json_payload.into_inner();
|
let req_payload = json_payload.into_inner();
|
||||||
|
let auth_id = query.into_inner().auth_id;
|
||||||
Box::pin(api::server_wrap(
|
Box::pin(api::server_wrap(
|
||||||
flow.clone(),
|
flow.clone(),
|
||||||
state,
|
state,
|
||||||
&http_req,
|
&http_req,
|
||||||
req_payload.clone(),
|
req_payload.clone(),
|
||||||
|state, _, req_body, _| user_core::signup_with_merchant_id(state, req_body),
|
|state, _, req_body, _| {
|
||||||
|
user_core::signup_with_merchant_id(state, req_body, auth_id.clone())
|
||||||
|
},
|
||||||
&auth::AdminApiAuth,
|
&auth::AdminApiAuth,
|
||||||
api_locking::LockAction::NotApplicable,
|
api_locking::LockAction::NotApplicable,
|
||||||
))
|
))
|
||||||
@ -113,15 +117,17 @@ pub async fn user_connect_account(
|
|||||||
state: web::Data<AppState>,
|
state: web::Data<AppState>,
|
||||||
http_req: HttpRequest,
|
http_req: HttpRequest,
|
||||||
json_payload: web::Json<user_api::ConnectAccountRequest>,
|
json_payload: web::Json<user_api::ConnectAccountRequest>,
|
||||||
|
query: web::Query<user_api::AuthIdQueryParam>,
|
||||||
) -> HttpResponse {
|
) -> HttpResponse {
|
||||||
let flow = Flow::UserConnectAccount;
|
let flow = Flow::UserConnectAccount;
|
||||||
let req_payload = json_payload.into_inner();
|
let req_payload = json_payload.into_inner();
|
||||||
|
let auth_id = query.into_inner().auth_id;
|
||||||
Box::pin(api::server_wrap(
|
Box::pin(api::server_wrap(
|
||||||
flow.clone(),
|
flow.clone(),
|
||||||
state,
|
state,
|
||||||
&http_req,
|
&http_req,
|
||||||
req_payload.clone(),
|
req_payload.clone(),
|
||||||
|state, _, req_body, _| user_core::connect_account(state, req_body),
|
|state, _, req_body, _| user_core::connect_account(state, req_body, auth_id.clone()),
|
||||||
&auth::NoAuth,
|
&auth::NoAuth,
|
||||||
api_locking::LockAction::NotApplicable,
|
api_locking::LockAction::NotApplicable,
|
||||||
))
|
))
|
||||||
@ -382,14 +388,16 @@ pub async fn forgot_password(
|
|||||||
state: web::Data<AppState>,
|
state: web::Data<AppState>,
|
||||||
req: HttpRequest,
|
req: HttpRequest,
|
||||||
payload: web::Json<user_api::ForgotPasswordRequest>,
|
payload: web::Json<user_api::ForgotPasswordRequest>,
|
||||||
|
query: web::Query<user_api::AuthIdQueryParam>,
|
||||||
) -> HttpResponse {
|
) -> HttpResponse {
|
||||||
let flow = Flow::ForgotPassword;
|
let flow = Flow::ForgotPassword;
|
||||||
|
let auth_id = query.into_inner().auth_id;
|
||||||
Box::pin(api::server_wrap(
|
Box::pin(api::server_wrap(
|
||||||
flow,
|
flow,
|
||||||
state.clone(),
|
state.clone(),
|
||||||
&req,
|
&req,
|
||||||
payload.into_inner(),
|
payload.into_inner(),
|
||||||
|state, _, payload, _| user_core::forgot_password(state, payload),
|
|state, _, payload, _| user_core::forgot_password(state, payload, auth_id.clone()),
|
||||||
&auth::NoAuth,
|
&auth::NoAuth,
|
||||||
api_locking::LockAction::NotApplicable,
|
api_locking::LockAction::NotApplicable,
|
||||||
))
|
))
|
||||||
@ -431,21 +439,31 @@ pub async fn reset_password(
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn invite_multiple_user(
|
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>,
|
token_only_query_param: web::Query<user_api::TokenOnlyQueryParam>,
|
||||||
|
auth_id_query_param: web::Query<user_api::AuthIdQueryParam>,
|
||||||
) -> HttpResponse {
|
) -> HttpResponse {
|
||||||
let flow = Flow::InviteMultipleUser;
|
let flow = Flow::InviteMultipleUser;
|
||||||
let is_token_only = query.into_inner().token_only;
|
let is_token_only = token_only_query_param.into_inner().token_only;
|
||||||
|
let auth_id = auth_id_query_param.into_inner().auth_id;
|
||||||
Box::pin(api::server_wrap(
|
Box::pin(api::server_wrap(
|
||||||
flow,
|
flow,
|
||||||
state.clone(),
|
state.clone(),
|
||||||
&req,
|
&req,
|
||||||
payload.into_inner(),
|
payload.into_inner(),
|
||||||
|state, user, payload, req_state| {
|
|state, user, payload, req_state| {
|
||||||
user_core::invite_multiple_user(state, user, payload, req_state, is_token_only)
|
user_core::invite_multiple_user(
|
||||||
|
state,
|
||||||
|
user,
|
||||||
|
payload,
|
||||||
|
req_state,
|
||||||
|
is_token_only,
|
||||||
|
auth_id.clone(),
|
||||||
|
)
|
||||||
},
|
},
|
||||||
&auth::JWTAuth(Permission::UsersWrite),
|
&auth::JWTAuth(Permission::UsersWrite),
|
||||||
api_locking::LockAction::NotApplicable,
|
api_locking::LockAction::NotApplicable,
|
||||||
@ -458,14 +476,18 @@ pub async fn resend_invite(
|
|||||||
state: web::Data<AppState>,
|
state: web::Data<AppState>,
|
||||||
req: HttpRequest,
|
req: HttpRequest,
|
||||||
payload: web::Json<user_api::ReInviteUserRequest>,
|
payload: web::Json<user_api::ReInviteUserRequest>,
|
||||||
|
query: web::Query<user_api::AuthIdQueryParam>,
|
||||||
) -> HttpResponse {
|
) -> HttpResponse {
|
||||||
let flow = Flow::ReInviteUser;
|
let flow = Flow::ReInviteUser;
|
||||||
|
let auth_id = query.into_inner().auth_id;
|
||||||
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::resend_invite,
|
|state, user, req_payload, _| {
|
||||||
|
user_core::resend_invite(state, user, req_payload, auth_id.clone())
|
||||||
|
},
|
||||||
&auth::JWTAuth(Permission::UsersWrite),
|
&auth::JWTAuth(Permission::UsersWrite),
|
||||||
api_locking::LockAction::NotApplicable,
|
api_locking::LockAction::NotApplicable,
|
||||||
))
|
))
|
||||||
@ -551,14 +573,16 @@ pub async fn verify_email_request(
|
|||||||
state: web::Data<AppState>,
|
state: web::Data<AppState>,
|
||||||
http_req: HttpRequest,
|
http_req: HttpRequest,
|
||||||
json_payload: web::Json<user_api::SendVerifyEmailRequest>,
|
json_payload: web::Json<user_api::SendVerifyEmailRequest>,
|
||||||
|
query: web::Query<user_api::AuthIdQueryParam>,
|
||||||
) -> HttpResponse {
|
) -> HttpResponse {
|
||||||
let flow = Flow::VerifyEmailRequest;
|
let flow = Flow::VerifyEmailRequest;
|
||||||
|
let auth_id = query.into_inner().auth_id;
|
||||||
Box::pin(api::server_wrap(
|
Box::pin(api::server_wrap(
|
||||||
flow,
|
flow,
|
||||||
state.clone(),
|
state.clone(),
|
||||||
&http_req,
|
&http_req,
|
||||||
json_payload.into_inner(),
|
json_payload.into_inner(),
|
||||||
|state, _, req_body, _| user_core::send_verification_mail(state, req_body),
|
|state, _, req_body, _| user_core::send_verification_mail(state, req_body, auth_id.clone()),
|
||||||
&auth::NoAuth,
|
&auth::NoAuth,
|
||||||
api_locking::LockAction::NotApplicable,
|
api_locking::LockAction::NotApplicable,
|
||||||
))
|
))
|
||||||
|
|||||||
@ -190,14 +190,21 @@ pub fn get_link_with_token(
|
|||||||
base_url: impl std::fmt::Display,
|
base_url: impl std::fmt::Display,
|
||||||
token: impl std::fmt::Display,
|
token: impl std::fmt::Display,
|
||||||
action: impl std::fmt::Display,
|
action: impl std::fmt::Display,
|
||||||
|
auth_id: &Option<impl std::fmt::Display>,
|
||||||
) -> String {
|
) -> String {
|
||||||
format!("{base_url}/user/{action}?token={token}")
|
let email_url = format!("{base_url}/user/{action}?token={token}");
|
||||||
|
if let Some(auth_id) = auth_id {
|
||||||
|
format!("{email_url}&auth_id={auth_id}")
|
||||||
|
} else {
|
||||||
|
email_url
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct VerifyEmail {
|
pub struct VerifyEmail {
|
||||||
pub recipient_email: domain::UserEmail,
|
pub recipient_email: domain::UserEmail,
|
||||||
pub settings: std::sync::Arc<configs::Settings>,
|
pub settings: std::sync::Arc<configs::Settings>,
|
||||||
pub subject: &'static str,
|
pub subject: &'static str,
|
||||||
|
pub auth_id: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Currently only HTML is supported
|
/// Currently only HTML is supported
|
||||||
@ -213,8 +220,12 @@ impl EmailData for VerifyEmail {
|
|||||||
.await
|
.await
|
||||||
.change_context(EmailError::TokenGenerationFailure)?;
|
.change_context(EmailError::TokenGenerationFailure)?;
|
||||||
|
|
||||||
let verify_email_link =
|
let verify_email_link = get_link_with_token(
|
||||||
get_link_with_token(&self.settings.email.base_url, token, "verify_email");
|
&self.settings.user.base_url,
|
||||||
|
token,
|
||||||
|
"verify_email",
|
||||||
|
&self.auth_id,
|
||||||
|
);
|
||||||
|
|
||||||
let body = html::get_html_body(EmailBody::Verify {
|
let body = html::get_html_body(EmailBody::Verify {
|
||||||
link: verify_email_link,
|
link: verify_email_link,
|
||||||
@ -233,6 +244,7 @@ pub struct ResetPassword {
|
|||||||
pub user_name: domain::UserName,
|
pub user_name: domain::UserName,
|
||||||
pub settings: std::sync::Arc<configs::Settings>,
|
pub settings: std::sync::Arc<configs::Settings>,
|
||||||
pub subject: &'static str,
|
pub subject: &'static str,
|
||||||
|
pub auth_id: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
@ -247,8 +259,12 @@ impl EmailData for ResetPassword {
|
|||||||
.await
|
.await
|
||||||
.change_context(EmailError::TokenGenerationFailure)?;
|
.change_context(EmailError::TokenGenerationFailure)?;
|
||||||
|
|
||||||
let reset_password_link =
|
let reset_password_link = get_link_with_token(
|
||||||
get_link_with_token(&self.settings.email.base_url, token, "set_password");
|
&self.settings.user.base_url,
|
||||||
|
token,
|
||||||
|
"set_password",
|
||||||
|
&self.auth_id,
|
||||||
|
);
|
||||||
|
|
||||||
let body = html::get_html_body(EmailBody::Reset {
|
let body = html::get_html_body(EmailBody::Reset {
|
||||||
link: reset_password_link,
|
link: reset_password_link,
|
||||||
@ -268,6 +284,7 @@ pub struct MagicLink {
|
|||||||
pub user_name: domain::UserName,
|
pub user_name: domain::UserName,
|
||||||
pub settings: std::sync::Arc<configs::Settings>,
|
pub settings: std::sync::Arc<configs::Settings>,
|
||||||
pub subject: &'static str,
|
pub subject: &'static str,
|
||||||
|
pub auth_id: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
@ -282,8 +299,12 @@ impl EmailData for MagicLink {
|
|||||||
.await
|
.await
|
||||||
.change_context(EmailError::TokenGenerationFailure)?;
|
.change_context(EmailError::TokenGenerationFailure)?;
|
||||||
|
|
||||||
let magic_link_login =
|
let magic_link_login = get_link_with_token(
|
||||||
get_link_with_token(&self.settings.email.base_url, token, "verify_email");
|
&self.settings.user.base_url,
|
||||||
|
token,
|
||||||
|
"verify_email",
|
||||||
|
&self.auth_id,
|
||||||
|
);
|
||||||
|
|
||||||
let body = html::get_html_body(EmailBody::MagicLink {
|
let body = html::get_html_body(EmailBody::MagicLink {
|
||||||
link: magic_link_login,
|
link: magic_link_login,
|
||||||
@ -305,6 +326,7 @@ pub struct InviteUser {
|
|||||||
pub settings: std::sync::Arc<configs::Settings>,
|
pub settings: std::sync::Arc<configs::Settings>,
|
||||||
pub subject: &'static str,
|
pub subject: &'static str,
|
||||||
pub merchant_id: String,
|
pub merchant_id: String,
|
||||||
|
pub auth_id: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
@ -319,8 +341,12 @@ impl EmailData for InviteUser {
|
|||||||
.await
|
.await
|
||||||
.change_context(EmailError::TokenGenerationFailure)?;
|
.change_context(EmailError::TokenGenerationFailure)?;
|
||||||
|
|
||||||
let invite_user_link =
|
let invite_user_link = get_link_with_token(
|
||||||
get_link_with_token(&self.settings.email.base_url, token, "set_password");
|
&self.settings.user.base_url,
|
||||||
|
token,
|
||||||
|
"set_password",
|
||||||
|
&self.auth_id,
|
||||||
|
);
|
||||||
|
|
||||||
let body = html::get_html_body(EmailBody::InviteUser {
|
let body = html::get_html_body(EmailBody::InviteUser {
|
||||||
link: invite_user_link,
|
link: invite_user_link,
|
||||||
@ -341,6 +367,7 @@ pub struct InviteRegisteredUser {
|
|||||||
pub settings: std::sync::Arc<configs::Settings>,
|
pub settings: std::sync::Arc<configs::Settings>,
|
||||||
pub subject: &'static str,
|
pub subject: &'static str,
|
||||||
pub merchant_id: String,
|
pub merchant_id: String,
|
||||||
|
pub auth_id: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
@ -356,9 +383,10 @@ impl EmailData for InviteRegisteredUser {
|
|||||||
.change_context(EmailError::TokenGenerationFailure)?;
|
.change_context(EmailError::TokenGenerationFailure)?;
|
||||||
|
|
||||||
let invite_user_link = get_link_with_token(
|
let invite_user_link = get_link_with_token(
|
||||||
&self.settings.email.base_url,
|
&self.settings.user.base_url,
|
||||||
token,
|
token,
|
||||||
"accept_invite_from_email",
|
"accept_invite_from_email",
|
||||||
|
&self.auth_id,
|
||||||
);
|
);
|
||||||
let body = html::get_html_body(EmailBody::AcceptInviteFromEmail {
|
let body = html::get_html_body(EmailBody::AcceptInviteFromEmail {
|
||||||
link: invite_user_link,
|
link: invite_user_link,
|
||||||
|
|||||||
Reference in New Issue
Block a user