mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-28 12:15:40 +08:00
feat(dashboard_metadata): Add email alert for Prod Intent (#3482)
Co-authored-by: Mani Chandra Dulam <mani.dchandra@juspay.in> Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
90a24625ce
commit
94cd7b6897
@ -1,2 +1,3 @@
|
|||||||
pub const MAX_NAME_LENGTH: usize = 70;
|
pub const MAX_NAME_LENGTH: usize = 70;
|
||||||
pub const MAX_COMPANY_NAME_LENGTH: usize = 70;
|
pub const MAX_COMPANY_NAME_LENGTH: usize = 70;
|
||||||
|
pub const BUSINESS_EMAIL: &str = "biz@hyperswitch.io";
|
||||||
|
|||||||
@ -3,7 +3,11 @@ use diesel_models::{
|
|||||||
enums::DashboardMetadata as DBEnum, user::dashboard_metadata::DashboardMetadata,
|
enums::DashboardMetadata as DBEnum, user::dashboard_metadata::DashboardMetadata,
|
||||||
};
|
};
|
||||||
use error_stack::ResultExt;
|
use error_stack::ResultExt;
|
||||||
|
#[cfg(feature = "email")]
|
||||||
|
use router_env::logger;
|
||||||
|
|
||||||
|
#[cfg(feature = "email")]
|
||||||
|
use crate::services::email::types as email_types;
|
||||||
use crate::{
|
use crate::{
|
||||||
core::errors::{UserErrors, UserResponse, UserResult},
|
core::errors::{UserErrors, UserResponse, UserResult},
|
||||||
routes::AppState,
|
routes::AppState,
|
||||||
@ -434,15 +438,31 @@ async fn insert_metadata(
|
|||||||
if utils::is_update_required(&metadata) {
|
if utils::is_update_required(&metadata) {
|
||||||
metadata = utils::update_user_scoped_metadata(
|
metadata = utils::update_user_scoped_metadata(
|
||||||
state,
|
state,
|
||||||
user.user_id,
|
user.user_id.clone(),
|
||||||
user.merchant_id,
|
user.merchant_id,
|
||||||
user.org_id,
|
user.org_id,
|
||||||
metadata_key,
|
metadata_key,
|
||||||
data,
|
data.clone(),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.change_context(UserErrors::InternalServerError);
|
.change_context(UserErrors::InternalServerError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "email")]
|
||||||
|
{
|
||||||
|
if utils::is_prod_email_required(&data) {
|
||||||
|
let email_contents = email_types::BizEmailProd::new(state, data)?;
|
||||||
|
let send_email_result = state
|
||||||
|
.email_client
|
||||||
|
.compose_and_send_email(
|
||||||
|
Box::new(email_contents),
|
||||||
|
state.conf.proxy.https_url.as_ref(),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
logger::info!(?send_email_result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
metadata
|
metadata
|
||||||
}
|
}
|
||||||
types::MetaData::SPTestPayment(data) => {
|
types::MetaData::SPTestPayment(data) => {
|
||||||
|
|||||||
138
crates/router/src/services/email/assets/bizemailprod.html
Normal file
138
crates/router/src/services/email/assets/bizemailprod.html
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
|
||||||
|
<title>Welcome to HyperSwitch!</title>
|
||||||
|
<body style="background-color: #ececec">
|
||||||
|
<div
|
||||||
|
id="wrapper"
|
||||||
|
style="
|
||||||
|
background-color: none;
|
||||||
|
margin: 0 auto;
|
||||||
|
text-align: center;
|
||||||
|
width: 90%;
|
||||||
|
-premailer-height: 200;
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<table
|
||||||
|
align="center"
|
||||||
|
class="main-table"
|
||||||
|
style="
|
||||||
|
-premailer-cellpadding: 0;
|
||||||
|
-premailer-cellspacing: 0;
|
||||||
|
background-color: #fff;
|
||||||
|
border: 0;
|
||||||
|
border-top: 5px solid #0165ef;
|
||||||
|
margin: 0 auto;
|
||||||
|
mso-table-lspace: 0;
|
||||||
|
mso-table-rspace: 0;
|
||||||
|
padding: 0 40;
|
||||||
|
text-align: center;
|
||||||
|
width: 100%;
|
||||||
|
"
|
||||||
|
bgcolor="#ffffff"
|
||||||
|
cellpadding="0"
|
||||||
|
cellspacing="0"
|
||||||
|
>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
class="spacer-sm"
|
||||||
|
style="
|
||||||
|
-premailer-height: 20;
|
||||||
|
-premailer-width: 80%;
|
||||||
|
line-height: 10px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 0;
|
||||||
|
"
|
||||||
|
width="100%"
|
||||||
|
></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
class="spacer-sm"
|
||||||
|
style="
|
||||||
|
-premailer-height: 20;
|
||||||
|
-premailer-width: 80%;
|
||||||
|
line-height: 10px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 0;
|
||||||
|
"
|
||||||
|
width="100%"
|
||||||
|
></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
class="copy"
|
||||||
|
style="
|
||||||
|
color: #666;
|
||||||
|
font-family: Roboto, Helvetica, Arial, san-serif;
|
||||||
|
font-size: 14px;
|
||||||
|
text-align: left;
|
||||||
|
line-height: 20px;
|
||||||
|
margin-top: 20px;
|
||||||
|
padding: 15px;
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<br />
|
||||||
|
<p>Hi Team,</p>
|
||||||
|
<p>
|
||||||
|
A Production Account Intent has been initiated by {username} -
|
||||||
|
please find more details below:
|
||||||
|
</p>
|
||||||
|
<ol>
|
||||||
|
<li><strong>Name:</strong> {username}</li>
|
||||||
|
<li><strong>Point of Contact Email (POC):</strong> {poc_email}</li>
|
||||||
|
<li><strong>Legal Business Name:</strong> {legal_business_name}</li>
|
||||||
|
<li><strong>Business Location:</strong> {business_location}</li>
|
||||||
|
<li><strong>Business Website:</strong> {business_website}</li>
|
||||||
|
</ol>
|
||||||
|
<br />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
class="spacer-sm"
|
||||||
|
style="
|
||||||
|
-premailer-height: 20;
|
||||||
|
-premailer-width: 80%;
|
||||||
|
line-height: 10px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 0;
|
||||||
|
"
|
||||||
|
width="100%"
|
||||||
|
></td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
class="headline"
|
||||||
|
style="
|
||||||
|
color: #444;
|
||||||
|
font-family: Roboto, Helvetica, Arial, san-serif;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 100;
|
||||||
|
line-height: 36px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 0;
|
||||||
|
text-align: center;
|
||||||
|
"
|
||||||
|
align="center"
|
||||||
|
>
|
||||||
|
Regards,<br />
|
||||||
|
Hyperswitch Dashboard Team
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
class="spacer-lg"
|
||||||
|
style="
|
||||||
|
-premailer-height: 75;
|
||||||
|
-premailer-width: 100%;
|
||||||
|
line-height: 30px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 0;
|
||||||
|
"
|
||||||
|
height="75"
|
||||||
|
width="100%"
|
||||||
|
></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
@ -1,11 +1,16 @@
|
|||||||
|
use api_models::user::dashboard_metadata::ProdIntent;
|
||||||
use common_utils::errors::CustomResult;
|
use common_utils::errors::CustomResult;
|
||||||
use error_stack::ResultExt;
|
use error_stack::ResultExt;
|
||||||
use external_services::email::{EmailContents, EmailData, EmailError};
|
use external_services::email::{EmailContents, EmailData, EmailError};
|
||||||
use masking::{ExposeInterface, PeekInterface};
|
use masking::{ExposeInterface, PeekInterface, Secret};
|
||||||
|
|
||||||
use crate::{configs, consts};
|
use crate::{configs, consts, routes::AppState};
|
||||||
#[cfg(feature = "olap")]
|
#[cfg(feature = "olap")]
|
||||||
use crate::{core::errors::UserErrors, services::jwt, types::domain};
|
use crate::{
|
||||||
|
core::errors::{UserErrors, UserResult},
|
||||||
|
services::jwt,
|
||||||
|
types::domain,
|
||||||
|
};
|
||||||
|
|
||||||
pub enum EmailBody {
|
pub enum EmailBody {
|
||||||
Verify {
|
Verify {
|
||||||
@ -23,6 +28,13 @@ pub enum EmailBody {
|
|||||||
link: String,
|
link: String,
|
||||||
user_name: String,
|
user_name: String,
|
||||||
},
|
},
|
||||||
|
BizEmailProd {
|
||||||
|
user_name: String,
|
||||||
|
poc_email: String,
|
||||||
|
legal_business_name: String,
|
||||||
|
business_location: String,
|
||||||
|
business_website: String,
|
||||||
|
},
|
||||||
ReconActivation {
|
ReconActivation {
|
||||||
user_name: String,
|
user_name: String,
|
||||||
},
|
},
|
||||||
@ -69,6 +81,22 @@ pub mod html {
|
|||||||
username = user_name,
|
username = user_name,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
EmailBody::BizEmailProd {
|
||||||
|
user_name,
|
||||||
|
poc_email,
|
||||||
|
legal_business_name,
|
||||||
|
business_location,
|
||||||
|
business_website,
|
||||||
|
} => {
|
||||||
|
format!(
|
||||||
|
include_str!("assets/bizemailprod.html"),
|
||||||
|
poc_email = poc_email,
|
||||||
|
legal_business_name = legal_business_name,
|
||||||
|
business_location = business_location,
|
||||||
|
business_website = business_website,
|
||||||
|
username = user_name,
|
||||||
|
)
|
||||||
|
}
|
||||||
EmailBody::ProFeatureRequest {
|
EmailBody::ProFeatureRequest {
|
||||||
feature_name,
|
feature_name,
|
||||||
merchant_id,
|
merchant_id,
|
||||||
@ -275,6 +303,56 @@ impl EmailData for ReconActivation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct BizEmailProd {
|
||||||
|
pub recipient_email: domain::UserEmail,
|
||||||
|
pub user_name: Secret<String>,
|
||||||
|
pub poc_email: Secret<String>,
|
||||||
|
pub legal_business_name: String,
|
||||||
|
pub business_location: String,
|
||||||
|
pub business_website: String,
|
||||||
|
pub settings: std::sync::Arc<configs::settings::Settings>,
|
||||||
|
pub subject: &'static str,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BizEmailProd {
|
||||||
|
pub fn new(state: &AppState, data: ProdIntent) -> UserResult<Self> {
|
||||||
|
Ok(Self {
|
||||||
|
recipient_email: (domain::UserEmail::new(
|
||||||
|
consts::user::BUSINESS_EMAIL.to_string().into(),
|
||||||
|
))?,
|
||||||
|
settings: state.conf.clone(),
|
||||||
|
subject: "New Prod Intent",
|
||||||
|
user_name: data.poc_name.unwrap_or_default().into(),
|
||||||
|
poc_email: data.poc_email.unwrap_or_default().into(),
|
||||||
|
legal_business_name: data.legal_business_name.unwrap_or_default(),
|
||||||
|
business_location: data
|
||||||
|
.business_location
|
||||||
|
.unwrap_or(common_enums::CountryAlpha2::AD)
|
||||||
|
.to_string(),
|
||||||
|
business_website: data.business_website.unwrap_or_default(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl EmailData for BizEmailProd {
|
||||||
|
async fn get_email_data(&self) -> CustomResult<EmailContents, EmailError> {
|
||||||
|
let body = html::get_html_body(EmailBody::BizEmailProd {
|
||||||
|
user_name: self.user_name.clone().expose(),
|
||||||
|
poc_email: self.poc_email.clone().expose(),
|
||||||
|
legal_business_name: self.legal_business_name.clone(),
|
||||||
|
business_location: self.business_location.clone(),
|
||||||
|
business_website: self.business_website.clone(),
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(EmailContents {
|
||||||
|
subject: self.subject.to_string(),
|
||||||
|
body: external_services::email::IntermediateString::new(body),
|
||||||
|
recipient: self.recipient_email.clone().into_inner(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct ProFeatureRequest {
|
pub struct ProFeatureRequest {
|
||||||
pub recipient_email: domain::UserEmail,
|
pub recipient_email: domain::UserEmail,
|
||||||
pub feature_name: String,
|
pub feature_name: String,
|
||||||
|
|||||||
@ -2,7 +2,7 @@ use std::{net::IpAddr, str::FromStr};
|
|||||||
|
|
||||||
use actix_web::http::header::HeaderMap;
|
use actix_web::http::header::HeaderMap;
|
||||||
use api_models::user::dashboard_metadata::{
|
use api_models::user::dashboard_metadata::{
|
||||||
GetMetaDataRequest, GetMultipleMetaDataPayload, SetMetaDataRequest,
|
GetMetaDataRequest, GetMultipleMetaDataPayload, ProdIntent, SetMetaDataRequest,
|
||||||
};
|
};
|
||||||
use diesel_models::{
|
use diesel_models::{
|
||||||
enums::DashboardMetadata as DBEnum,
|
enums::DashboardMetadata as DBEnum,
|
||||||
@ -276,3 +276,10 @@ pub fn parse_string_to_enums(query: String) -> UserResult<GetMultipleMetaDataPay
|
|||||||
.attach_printable("Error Parsing to DashboardMetadata enums")?,
|
.attach_printable("Error Parsing to DashboardMetadata enums")?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_prod_email_required(data: &ProdIntent) -> bool {
|
||||||
|
!(data
|
||||||
|
.poc_email
|
||||||
|
.as_ref()
|
||||||
|
.map_or(true, |mail| mail.contains("juspay")))
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user