[MM-43337] Updating email templates for trial will end and trial ended emails (#19976)

* Updating email templates for trial will end and trial will end emails

* put back variable

* Rebuilding

* fix tests

* Updates

* [MM-43339] Add Cloud Subscription Upgrade Confirmation Email (#19989)

* Add Cloud Upgrade Confirmation email

* Updates

* String change

* i18n-extract

* Updates

* make email-mocks

* Appease linter

* Add a test

* GMAIL NEVER RENDERS RIGHT

* Important EVERYWHERE because gmail just cant deal

* l

* Last one

* Update image

* Update tests

* Fix tests

Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
Этот коммит содержится в:
Nick Misasi
2022-04-28 10:06:16 -04:00
коммит произвёл GitHub
родитель 9ee41765f7
Коммит 373c4655e6
24 изменённых файлов: 975 добавлений и 194 удалений

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

@@ -980,6 +980,7 @@ type AppIface interface {
SendPasswordReset(email string, siteURL string) (bool, *model.AppError)
SendPaymentFailedEmail(failedPayment *model.FailedPayment) *model.AppError
SendTestPushNotification(deviceID string) string
SendUpgradeConfirmationEmail() *model.AppError
ServeInterPluginRequest(w http.ResponseWriter, r *http.Request, sourcePluginId, destinationPluginId string)
SessionHasPermissionTo(session model.Session, permission *model.Permission) bool
SessionHasPermissionToAny(session model.Session, permissions []*model.Permission) bool

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

@@ -4,7 +4,9 @@
package app
import (
"fmt"
"net/http"
"time"
"github.com/mattermost/mattermost-server/v6/model"
"github.com/mattermost/mattermost-server/v6/shared/mlog"
@@ -35,6 +37,50 @@ func (a *App) SendPaymentFailedEmail(failedPayment *model.FailedPayment) *model.
return nil
}
func (a *App) SendUpgradeConfirmationEmail() *model.AppError {
sysAdmins, e := a.getSysAdminsEmailRecipients()
if e != nil {
return e
}
if len(sysAdmins) == 0 {
return model.NewAppError("app.SendCloudUpgradeConfirmationEmail", "app.user.send_emails.app_error", nil, "", http.StatusInternalServerError)
}
subscription, err := a.Cloud().GetSubscription("")
if err != nil {
return model.NewAppError("app.SendCloudUpgradeConfirmationEmail", "app.user.send_emails.app_error", nil, "", http.StatusInternalServerError)
}
// Build readable trial end date
endTimeStamp := subscription.TrialEndAt
t := time.Unix(endTimeStamp, 0)
trialEndDate := fmt.Sprintf("%s %d, %d", t.Month(), t.Day(), t.Year())
// we want to at least have one email sent out to an admin
countNotOks := 0
for _, admin := range sysAdmins {
name := admin.FirstName
if name == "" {
name = admin.Username
}
err := a.Srv().EmailService.SendCloudUpgradeConfirmationEmail(admin.Email, name, trialEndDate, admin.Locale, *a.Config().ServiceSettings.SiteURL, subscription.GetWorkSpaceNameFromDNS())
if err != nil {
a.Log().Error("Error sending trial ended email to", mlog.String("email", admin.Email), mlog.Err(err))
countNotOks++
}
}
// if not even one admin got an email, we consider that this operation errored
if countNotOks == len(sysAdmins) {
return model.NewAppError("app.SendCloudUpgradeConfirmationEmail", "app.user.send_emails.app_error", nil, "", http.StatusInternalServerError)
}
return nil
}
// SendNoCardPaymentFailedEmail
func (a *App) SendNoCardPaymentFailedEmail() *model.AppError {
sysAdmins, err := a.getSysAdminsEmailRecipients()

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

@@ -226,6 +226,32 @@ func (es *Service) SendWelcomeEmail(userID string, email string, verified bool,
return nil
}
func (es *Service) SendCloudUpgradeConfirmationEmail(userEmail, name, trialEndDate, locale, siteURL, workspaceName string) error {
T := i18n.GetUserTranslations(locale)
subject := T("api.templates.cloud_upgrade_confirmation.subject")
data := es.NewEmailTemplateData(locale)
data.Props["Title"] = T("api.templates.cloud_upgrade_confirmation.title")
data.Props["SubTitle"] = T("api.templates.cloud_upgrade_confirmation.subtitle", map[string]interface{}{"WorkspaceName": workspaceName, "TrialEnd": trialEndDate})
data.Props["SiteURL"] = siteURL
data.Props["ButtonURL"] = siteURL
data.Props["Button"] = T("api.templates.cloud_welcome_email.button")
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
body, err := es.templatesContainer.RenderToString("cloud_upgrade_confirmation", data)
if err != nil {
return err
}
if err := es.sendEmailWithCustomReplyTo(userEmail, subject, body, *es.config().SupportSettings.SupportEmail); err != nil {
return err
}
return nil
}
func (es *Service) SendCloudTrialEndWarningEmail(userEmail, name, trialEndDate, locale, siteURL string) error {
T := i18n.GetUserTranslations(locale)
subject := T("api.templates.cloud_trial_ending_email.subject")

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

@@ -189,6 +189,9 @@ func TestSendCloudTrialEndWarningEmail(t *testing.T) {
emailTo := "testclouduser@example.com"
emailToUsername := strings.Split(emailTo, "@")[0]
th.UpdateConfig(func(cfg *model.Config) {
*cfg.SupportSettings.SupportEmail = "support@mattermost.com"
})
t.Run("SendCloudTrialEndWarningEmail", func(t *testing.T) {
verifyMailbox := func(t *testing.T) {
@@ -212,7 +215,7 @@ func TestSendCloudTrialEndWarningEmail(t *testing.T) {
require.Contains(t, resultsEmail.Body.HTML, emailToUsername, "Wrong received message %s", resultsEmail.Body.Text)
require.Contains(t, resultsEmail.Body.Text, "http://testserver", "Wrong received message %s", resultsEmail.Body.Text)
require.Contains(t, resultsEmail.Body.Text, emailToUsername, "Wrong received message %s", resultsEmail.Body.Text)
require.Contains(t, resultsEmail.Body.Text, "feedback-cloud@mattermost.com")
require.Contains(t, resultsEmail.Body.Text, "support@mattermost.com")
}
mail.DeleteMailBox(emailTo)
@@ -249,8 +252,7 @@ func TestSendCloudTrialEndedEmail(t *testing.T) {
require.Contains(t, resultsMailbox[0].To[0], emailTo, "Wrong To: recipient")
resultsEmail, err := mail.GetMessageFromMailbox(emailTo, resultsMailbox[0].ID)
require.NoError(t, err, "Could not get message from mailbox")
require.Contains(t, resultsEmail.Body.Text, "your 14-day free trial of Mattermost Cloud Enterprise has ended today", "Wrong received message %s", resultsEmail.Body.Text)
require.Contains(t, resultsEmail.Body.Text, "we will delete your Cloud workspace permanently", "Wrong received message %s", resultsEmail.Body.Text)
require.Contains(t, resultsEmail.Body.Text, "Your free 14-day trial of Mattermost has ended", "Wrong received message %s", resultsEmail.Body.Text)
}
mail.DeleteMailBox(emailTo)
@@ -261,6 +263,44 @@ func TestSendCloudTrialEndedEmail(t *testing.T) {
})
}
func TestSendCloudUpgradedEmail(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
th.ConfigureInbucketMail()
emailTo := "testclouduser@example.com"
emailToUsername := strings.Split(emailTo, "@")[0]
t.Run("SendCloudUpgradedEmail", func(t *testing.T) {
verifyMailbox := func(t *testing.T) {
t.Helper()
var resultsMailbox mail.JSONMessageHeaderInbucket
err2 := mail.RetryInbucket(5, func() error {
var err error
resultsMailbox, err = mail.GetMailBox(emailTo)
return err
})
if err2 != nil {
t.Skipf("No email was received, maybe due load on the server: %v", err2)
}
require.Len(t, resultsMailbox, 1)
require.Contains(t, resultsMailbox[0].To[0], emailTo, "Wrong To: recipient")
resultsEmail, err := mail.GetMessageFromMailbox(emailTo, resultsMailbox[0].ID)
require.NoError(t, err, "Could not get message from mailbox")
require.Contains(t, resultsEmail.Body.Text, "You are now upgraded!", "Wrong received message %s", resultsEmail.Body.Text)
require.Contains(t, resultsEmail.Body.Text, "SomeName workspace has now been upgraded", "Wrong received message %s", resultsEmail.Body.Text)
}
mail.DeleteMailBox(emailTo)
err := th.service.SendCloudUpgradeConfirmationEmail(emailTo, emailToUsername, "June 23, 2200", th.BasicUser.Locale, "https://example.com", "SomeName")
require.NoError(t, err)
verifyMailbox(t)
})
}
func TestMailServiceConfig(t *testing.T) {
configuredReplyTo := "feedbackexample@test.com"
customReplyTo := "customreplyto@test.com"

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

@@ -153,6 +153,20 @@ func (_m *ServiceInterface) SendCloudTrialEndedEmail(userEmail string, name stri
return r0
}
// SendCloudUpgradeConfirmationEmail provides a mock function with given fields: userEmail, name, trialEndDate, locale, siteURL, workspaceName
func (_m *ServiceInterface) SendCloudUpgradeConfirmationEmail(userEmail string, name string, trialEndDate string, locale string, siteURL string, workspaceName string) error {
ret := _m.Called(userEmail, name, trialEndDate, locale, siteURL, workspaceName)
var r0 error
if rf, ok := ret.Get(0).(func(string, string, string, string, string, string) error); ok {
r0 = rf(userEmail, name, trialEndDate, locale, siteURL, workspaceName)
} else {
r0 = ret.Error(0)
}
return r0
}
// SendCloudWelcomeEmail provides a mock function with given fields: userEmail, locale, teamInviteID, workSpaceName, dns, siteURL
func (_m *ServiceInterface) SendCloudWelcomeEmail(userEmail string, locale string, teamInviteID string, workSpaceName string, dns string, siteURL string) error {
ret := _m.Called(userEmail, locale, teamInviteID, workSpaceName, dns, siteURL)

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

@@ -131,6 +131,7 @@ type ServiceInterface interface {
SendWelcomeEmail(userID string, email string, verified bool, disableWelcomeEmail bool, locale, siteURL, redirect string) error
SendCloudTrialEndWarningEmail(userEmail, name, trialEndDate, locale, siteURL string) error
SendCloudTrialEndedEmail(userEmail, name, locale, siteURL string) error
SendCloudUpgradeConfirmationEmail(userEmail, name, trialEndDate, locale, siteURL, workspaceName string) error
SendCloudWelcomeEmail(userEmail, locale, teamInviteID, workSpaceName, dns, siteURL string) error
SendPasswordChangeEmail(email, method, locale, siteURL string) error
SendUserAccessTokenAddedEmail(email, locale, siteURL string) error

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

@@ -14737,6 +14737,28 @@ func (a *OpenTracingAppLayer) SendTestPushNotification(deviceID string) string {
return resultVar0
}
func (a *OpenTracingAppLayer) SendUpgradeConfirmationEmail() *model.AppError {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.SendUpgradeConfirmationEmail")
a.ctx = newCtx
a.app.Srv().Store.SetContext(newCtx)
defer func() {
a.app.Srv().Store.SetContext(origCtx)
a.ctx = origCtx
}()
defer span.Finish()
resultVar0 := a.app.SendUpgradeConfirmationEmail()
if resultVar0 != nil {
span.LogFields(spanlog.Error(resultVar0))
ext.Error.Set(span, true)
}
return resultVar0
}
func (a *OpenTracingAppLayer) ServeInterPluginRequest(w http.ResponseWriter, r *http.Request, sourcePluginId string, destinationPluginId string) {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.ServeInterPluginRequest")