[MM-43399] Cloud Delinquency Email Sequence (#20814)

* Add DelinquentSince to Subscription fields

* Stashing, migrating

* Adding file

* Adding many email templates

* Fix templates pipeline

* Fix translations

* Fix mocks

* Many changes

* Adjust mocks

* Update i18n/en.json

Co-authored-by: Maria A Nunez <maria.nunez@mattermost.com>

* PR fixes

* Update string

* Update i18n/en.json

Co-authored-by: Maria A Nunez <maria.nunez@mattermost.com>

* Update URL's for buttons to open the delinquency modal

* Update emails from mjml

Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
Co-authored-by: Maria A Nunez <maria.nunez@mattermost.com>
Этот коммит содержится в:
Nick Misasi
2022-08-25 09:39:35 -04:00
коммит произвёл GitHub
родитель e9cc35122f
Коммит e8a45a8cf7
34 изменённых файлов: 3839 добавлений и 18 удалений

Просмотреть файл

@@ -1000,6 +1000,225 @@ func (es *Service) SendNoCardPaymentFailedEmail(email string, locale string, sit
return nil
}
func (es *Service) SendDelinquencyEmail7(email, locale, siteURL, planName string) error {
T := i18n.GetUserTranslations(locale)
subject := T("api.templates.payment_failed.subject")
data := es.NewEmailTemplateData(locale)
data.Props["SiteURL"] = siteURL
data.Props["Title"] = T("api.templates.delinquency_7.title")
data.Props["SubTitle1"] = T("api.templates.delinquency_7.subtitle1")
data.Props["SubTitle2"] = T("api.templates.delinquency_7.subtitle2", map[string]any{"Plan": planName})
data.Props["QuestionTitle"] = T("api.templates.questions_footer.title")
data.Props["QuestionInfo"] = T("api.templates.questions_footer.info")
data.Props["SupportEmail"] = *es.config().SupportSettings.SupportEmail
data.Props["Button"] = T("api.templates.delinquency_7.button")
data.Props["EmailUs"] = T("api.templates.email_us_anytime_at")
data.Props["Footer"] = T("api.templates.copyright")
body, err := es.templatesContainer.RenderToString("cloud_7_day_arrears", data)
if err != nil {
return err
}
if err := es.sendEmailWithCustomReplyTo(email, subject, body, *es.config().SupportSettings.SupportEmail); err != nil {
return err
}
return nil
}
func (es *Service) SendDelinquencyEmail14(email, locale, siteURL, planName string) error {
T := i18n.GetUserTranslations(locale)
subject := T("api.templates.delinquency_14.subject", map[string]any{"Plan": planName})
data := es.NewEmailTemplateData(locale)
data.Props["SiteURL"] = siteURL
data.Props["Title"] = T("api.templates.delinquency_14.title")
data.Props["SubTitle1"] = T("api.templates.delinquency_14.subtitle1")
data.Props["SubTitle2"] = T("api.templates.delinquency_14.subtitle2")
data.Props["QuestionTitle"] = T("api.templates.questions_footer.title")
data.Props["QuestionInfo"] = T("api.templates.questions_footer.info")
data.Props["SupportEmail"] = *es.config().SupportSettings.SupportEmail
data.Props["Button"] = T("api.templates.delinquency_14.button")
data.Props["EmailUs"] = T("api.templates.email_us_anytime_at")
data.Props["Footer"] = T("api.templates.copyright")
body, err := es.templatesContainer.RenderToString("cloud_14_day_arrears", data)
if err != nil {
return err
}
if err := es.sendEmailWithCustomReplyTo(email, subject, body, *es.config().SupportSettings.SupportEmail); err != nil {
return err
}
return nil
}
func (es *Service) SendDelinquencyEmail30(email, locale, siteURL, planName string) error {
T := i18n.GetUserTranslations(locale)
subject := T("api.templates.delinquency_30.subject", map[string]any{"Plan": planName})
data := es.NewEmailTemplateData(locale)
data.Props["SiteURL"] = siteURL
data.Props["Title"] = T("api.templates.delinquency_30.title")
data.Props["SubTitle1"] = T("api.templates.delinquency_30.subtitle1", map[string]any{"Plan": planName})
data.Props["SubTitle2"] = T("api.templates.delinquency_30.subtitle2")
data.Props["QuestionTitle"] = T("api.templates.questions_footer.title")
data.Props["QuestionInfo"] = T("api.templates.questions_footer.info")
data.Props["SupportEmail"] = *es.config().SupportSettings.SupportEmail
data.Props["Button"] = T("api.templates.delinquency_30.button")
data.Props["EmailUs"] = T("api.templates.email_us_anytime_at")
data.Props["BulletListItems"] = []string{T("api.templates.delinquency_30.bullet.message_history"), T("api.templates.delinquency_30.bullet.files"), T("api.templates.delinquency_30.bullet.cards"), T("api.templates.delinquency_30.bullet.plugins")}
data.Props["LimitsDocs"] = T("api.templates.delinquency_30.limits_documentation")
data.Props["Footer"] = T("api.templates.copyright")
body, err := es.templatesContainer.RenderToString("cloud_30_day_arrears", data)
if err != nil {
return err
}
if err := es.sendEmailWithCustomReplyTo(email, subject, body, *es.config().SupportSettings.SupportEmail); err != nil {
return err
}
return nil
}
func (es *Service) SendDelinquencyEmail45(email, locale, siteURL, planName, delinquencyDate string) error {
T := i18n.GetUserTranslations(locale)
subject := T("api.templates.delinquency_45.subject", map[string]any{"Plan": planName})
data := es.NewEmailTemplateData(locale)
data.Props["SiteURL"] = siteURL
data.Props["Title"] = T("api.templates.delinquency_45.title")
data.Props["SubTitle1"] = T("api.templates.delinquency_45.subtitle1", map[string]any{"DelinquencyDate": delinquencyDate})
data.Props["SubTitle2"] = T("api.templates.delinquency_45.subtitle2")
data.Props["SubTitle3"] = T("api.templates.delinquency_45.subtitle3")
data.Props["QuestionTitle"] = T("api.templates.questions_footer.title")
data.Props["QuestionInfo"] = T("api.templates.questions_footer.info")
data.Props["SupportEmail"] = *es.config().SupportSettings.SupportEmail
data.Props["Button"] = T("api.templates.delinquency_45.button")
data.Props["IncludeSecondaryActionButton"] = false
data.Props["EmailUs"] = T("api.templates.email_us_anytime_at")
data.Props["Footer"] = T("api.templates.copyright")
body, err := es.templatesContainer.RenderToString("cloud_45_day_arrears", data)
if err != nil {
return err
}
if err := es.sendEmailWithCustomReplyTo(email, subject, body, *es.config().SupportSettings.SupportEmail); err != nil {
return err
}
return nil
}
func (es *Service) SendDelinquencyEmail60(email, locale, siteURL string) error {
T := i18n.GetUserTranslations(locale)
subject := T("api.templates.delinquency_60.subject")
data := es.NewEmailTemplateData(locale)
data.Props["SiteURL"] = siteURL
data.Props["Title"] = T("api.templates.delinquency_60.title")
data.Props["SubTitle1"] = T("api.templates.delinquency_60.subtitle1")
data.Props["SubTitle2"] = T("api.templates.delinquency_60.subtitle2")
data.Props["SubTitle3"] = T("api.templates.delinquency_60.subtitle3")
data.Props["QuestionTitle"] = T("api.templates.questions_footer.title")
data.Props["QuestionInfo"] = T("api.templates.questions_footer.info")
data.Props["SupportEmail"] = *es.config().SupportSettings.SupportEmail
data.Props["Button"] = T("api.templates.delinquency_60.button")
data.Props["EmailUs"] = T("api.templates.email_us_anytime_at")
data.Props["IncludeSecondaryActionButton"] = true
data.Props["SecondaryActionButtonText"] = T("api.templates.delinquency_60.downgrade_to_starter")
data.Props["Footer"] = T("api.templates.copyright")
// 45 day template is the same as the 60 day one so its reused
body, err := es.templatesContainer.RenderToString("cloud_45_day_arrears", data)
if err != nil {
return err
}
if err := es.sendEmailWithCustomReplyTo(email, subject, body, *es.config().SupportSettings.SupportEmail); err != nil {
return err
}
return nil
}
func (es *Service) SendDelinquencyEmail75(email, locale, siteURL, planName, delinquencyDate string) error {
T := i18n.GetUserTranslations(locale)
subject := T("api.templates.delinquency_75.subject", map[string]any{"Plan": planName})
data := es.NewEmailTemplateData(locale)
data.Props["SiteURL"] = siteURL
data.Props["Title"] = T("api.templates.delinquency_75.title")
data.Props["SubTitle1"] = T("api.templates.delinquency_75.subtitle1", map[string]any{"DelinquencyDate": delinquencyDate})
data.Props["SubTitle2"] = T("api.templates.delinquency_75.subtitle2", map[string]any{"Plan": planName})
data.Props["SubTitle3"] = T("api.templates.delinquency_75.subtitle3")
data.Props["QuestionTitle"] = T("api.templates.questions_footer.title")
data.Props["QuestionInfo"] = T("api.templates.questions_footer.info")
data.Props["SupportEmail"] = *es.config().SupportSettings.SupportEmail
data.Props["Button"] = T("api.templates.delinquency_75.button")
data.Props["EmailUs"] = T("api.templates.email_us_anytime_at")
data.Props["IncludeSecondaryActionButton"] = true
data.Props["SecondaryActionButtonText"] = T("api.templates.delinquency_75.downgrade_to_starter")
data.Props["Footer"] = T("api.templates.copyright")
// 45 day template is the same as the 75 day one so its reused
body, err := es.templatesContainer.RenderToString("cloud_45_day_arrears", data)
if err != nil {
return err
}
if err := es.sendEmailWithCustomReplyTo(email, subject, body, *es.config().SupportSettings.SupportEmail); err != nil {
return err
}
return nil
}
func (es *Service) SendDelinquencyEmail90(email, locale, siteURL string) error {
T := i18n.GetUserTranslations(locale)
subject := T("api.templates.delinquency_90.subject")
data := es.NewEmailTemplateData(locale)
data.Props["SiteURL"] = siteURL
data.Props["Title"] = T("api.templates.delinquency_90.title")
data.Props["SubTitle1"] = T("api.templates.delinquency_90.subtitle1", map[string]any{"SiteURL": siteURL})
data.Props["SubTitle2"] = T("api.templates.delinquency_90.subtitle2")
data.Props["SubTitle3"] = T("api.templates.delinquency_90.subtitle3")
data.Props["QuestionTitle"] = T("api.templates.questions_footer.title")
data.Props["QuestionInfo"] = T("api.templates.questions_footer.info")
data.Props["SupportEmail"] = *es.config().SupportSettings.SupportEmail
data.Props["Button"] = T("api.templates.delinquency_90.button")
data.Props["EmailUs"] = T("api.templates.email_us_anytime_at")
data.Props["IncludeSecondaryActionButton"] = true
data.Props["SecondaryActionButtonText"] = T("api.templates.delinquency_90.secondary_action_button")
data.Props["Footer"] = T("api.templates.copyright")
body, err := es.templatesContainer.RenderToString("cloud_90_day_arrears", data)
if err != nil {
return err
}
if err := es.sendEmailWithCustomReplyTo(email, subject, body, *es.config().SupportSettings.SupportEmail); err != nil {
return err
}
return nil
}
// SendRemoveExpiredLicenseEmail formats an email and uses the email service to send the email to user with link pointing to CWS
// to renew the user license
func (es *Service) SendRemoveExpiredLicenseEmail(renewalLink, email string, locale, siteURL string) error {

Просмотреть файл

@@ -167,6 +167,104 @@ func (_m *ServiceInterface) SendDeactivateAccountEmail(_a0 string, locale string
return r0
}
// SendDelinquencyEmail14 provides a mock function with given fields: _a0, locale, siteURL, planName
func (_m *ServiceInterface) SendDelinquencyEmail14(_a0 string, locale string, siteURL string, planName string) error {
ret := _m.Called(_a0, locale, siteURL, planName)
var r0 error
if rf, ok := ret.Get(0).(func(string, string, string, string) error); ok {
r0 = rf(_a0, locale, siteURL, planName)
} else {
r0 = ret.Error(0)
}
return r0
}
// SendDelinquencyEmail30 provides a mock function with given fields: _a0, locale, siteURL, planName
func (_m *ServiceInterface) SendDelinquencyEmail30(_a0 string, locale string, siteURL string, planName string) error {
ret := _m.Called(_a0, locale, siteURL, planName)
var r0 error
if rf, ok := ret.Get(0).(func(string, string, string, string) error); ok {
r0 = rf(_a0, locale, siteURL, planName)
} else {
r0 = ret.Error(0)
}
return r0
}
// SendDelinquencyEmail45 provides a mock function with given fields: _a0, locale, siteURL, planName, delinquencyDate
func (_m *ServiceInterface) SendDelinquencyEmail45(_a0 string, locale string, siteURL string, planName string, delinquencyDate string) error {
ret := _m.Called(_a0, locale, siteURL, planName, delinquencyDate)
var r0 error
if rf, ok := ret.Get(0).(func(string, string, string, string, string) error); ok {
r0 = rf(_a0, locale, siteURL, planName, delinquencyDate)
} else {
r0 = ret.Error(0)
}
return r0
}
// SendDelinquencyEmail60 provides a mock function with given fields: _a0, locale, siteURL
func (_m *ServiceInterface) SendDelinquencyEmail60(_a0 string, locale string, siteURL string) error {
ret := _m.Called(_a0, locale, siteURL)
var r0 error
if rf, ok := ret.Get(0).(func(string, string, string) error); ok {
r0 = rf(_a0, locale, siteURL)
} else {
r0 = ret.Error(0)
}
return r0
}
// SendDelinquencyEmail7 provides a mock function with given fields: _a0, locale, siteURL, planName
func (_m *ServiceInterface) SendDelinquencyEmail7(_a0 string, locale string, siteURL string, planName string) error {
ret := _m.Called(_a0, locale, siteURL, planName)
var r0 error
if rf, ok := ret.Get(0).(func(string, string, string, string) error); ok {
r0 = rf(_a0, locale, siteURL, planName)
} else {
r0 = ret.Error(0)
}
return r0
}
// SendDelinquencyEmail75 provides a mock function with given fields: _a0, locale, siteURL, planName, delinquencyDate
func (_m *ServiceInterface) SendDelinquencyEmail75(_a0 string, locale string, siteURL string, planName string, delinquencyDate string) error {
ret := _m.Called(_a0, locale, siteURL, planName, delinquencyDate)
var r0 error
if rf, ok := ret.Get(0).(func(string, string, string, string, string) error); ok {
r0 = rf(_a0, locale, siteURL, planName, delinquencyDate)
} else {
r0 = ret.Error(0)
}
return r0
}
// SendDelinquencyEmail90 provides a mock function with given fields: _a0, locale, siteURL
func (_m *ServiceInterface) SendDelinquencyEmail90(_a0 string, locale string, siteURL string) error {
ret := _m.Called(_a0, locale, siteURL)
var r0 error
if rf, ok := ret.Get(0).(func(string, string, string) error); ok {
r0 = rf(_a0, locale, siteURL)
} else {
r0 = ret.Error(0)
}
return r0
}
// SendEmailChangeEmail provides a mock function with given fields: oldEmail, newEmail, locale, siteURL
func (_m *ServiceInterface) SendEmailChangeEmail(oldEmail string, newEmail string, locale string, siteURL string) error {
ret := _m.Called(oldEmail, newEmail, locale, siteURL)

Просмотреть файл

@@ -143,6 +143,14 @@ type ServiceInterface interface {
SendMailWithEmbeddedFiles(to, subject, htmlBody string, embeddedFiles map[string]io.Reader, messageID string, inReplyTo string, references string) error
SendLicenseUpForRenewalEmail(email, name, locale, siteURL, renewalLink string, daysToExpiration int) error
SendPaymentFailedEmail(email string, locale string, failedPayment *model.FailedPayment, siteURL string) (bool, error)
// Cloud delinquency email sequence
SendDelinquencyEmail7(email, locale, siteURL, planName string) error
SendDelinquencyEmail14(email, locale, siteURL, planName string) error
SendDelinquencyEmail30(email, locale, siteURL, planName string) error
SendDelinquencyEmail45(email, locale, siteURL, planName, delinquencyDate string) error
SendDelinquencyEmail60(email, locale, siteURL string) error
SendDelinquencyEmail75(email, locale, siteURL, planName, delinquencyDate string) error
SendDelinquencyEmail90(email, locale, siteURL string) error
SendNoCardPaymentFailedEmail(email string, locale string, siteURL string) error
SendRemoveExpiredLicenseEmail(renewalLink, email string, locale, siteURL string) error
AddNotificationEmailToBatch(user *model.User, post *model.Post, team *model.Team) *model.AppError