diff --git a/app/app.go b/app/app.go
index 804fa1c1fb..0b283b44f2 100644
--- a/app/app.go
+++ b/app/app.go
@@ -6,7 +6,6 @@ package app
import (
"context"
"fmt"
- "html/template"
"net/http"
"strconv"
"strings"
@@ -21,6 +20,7 @@ import (
"github.com/mattermost/mattermost-server/v5/services/timezones"
"github.com/mattermost/mattermost-server/v5/shared/i18n"
"github.com/mattermost/mattermost-server/v5/shared/mlog"
+ "github.com/mattermost/mattermost-server/v5/shared/templates"
"github.com/mattermost/mattermost-server/v5/utils"
)
@@ -148,12 +148,8 @@ func (a *App) TelemetryId() string {
return a.Srv().TelemetryId()
}
-func (s *Server) HTMLTemplates() *template.Template {
- if s.htmlTemplateWatcher != nil {
- return s.htmlTemplateWatcher.Templates()
- }
-
- return nil
+func (s *Server) TemplatesContainer() *templates.Container {
+ return s.htmlTemplateWatcher
}
func (a *App) Handle404(w http.ResponseWriter, r *http.Request) {
@@ -467,25 +463,25 @@ func (a *App) NotifyAndSetWarnMetricAck(warnMetricId string, sender *model.User,
return model.NewAppError("NotifyAndSetWarnMetricAck", "api.email.send_warn_metric_ack.missing_server.app_error", nil, i18n.T("api.context.invalid_param.app_error", map[string]interface{}{"Name": "SMTPServer"}), http.StatusInternalServerError)
}
T := i18n.GetUserTranslations(sender.Locale)
- bodyPage := a.Srv().EmailService.newEmailTemplate("warn_metric_ack", sender.Locale)
- bodyPage.Props["ContactNameHeader"] = T("api.templates.warn_metric_ack.body.contact_name_header")
- bodyPage.Props["ContactNameValue"] = sender.GetFullName()
- bodyPage.Props["ContactEmailHeader"] = T("api.templates.warn_metric_ack.body.contact_email_header")
- bodyPage.Props["ContactEmailValue"] = sender.Email
+ data := a.Srv().EmailService.newEmailTemplateData(sender.Locale)
+ data.Props["ContactNameHeader"] = T("api.templates.warn_metric_ack.body.contact_name_header")
+ data.Props["ContactNameValue"] = sender.GetFullName()
+ data.Props["ContactEmailHeader"] = T("api.templates.warn_metric_ack.body.contact_email_header")
+ data.Props["ContactEmailValue"] = sender.Email
//same definition as the active users count metric displayed in the SystemConsole Analytics section
registeredUsersCount, cerr := a.Srv().Store.User().Count(model.UserCountOptions{})
if cerr != nil {
mlog.Warn("Error retrieving the number of registered users", mlog.Err(cerr))
} else {
- bodyPage.Props["RegisteredUsersHeader"] = T("api.templates.warn_metric_ack.body.registered_users_header")
- bodyPage.Props["RegisteredUsersValue"] = registeredUsersCount
+ data.Props["RegisteredUsersHeader"] = T("api.templates.warn_metric_ack.body.registered_users_header")
+ data.Props["RegisteredUsersValue"] = registeredUsersCount
}
- bodyPage.Props["SiteURLHeader"] = T("api.templates.warn_metric_ack.body.site_url_header")
- bodyPage.Props["SiteURL"] = a.GetSiteURL()
- bodyPage.Props["TelemetryIdHeader"] = T("api.templates.warn_metric_ack.body.diagnostic_id_header")
- bodyPage.Props["TelemetryIdValue"] = a.TelemetryId()
- bodyPage.Props["Footer"] = T("api.templates.warn_metric_ack.footer")
+ data.Props["SiteURLHeader"] = T("api.templates.warn_metric_ack.body.site_url_header")
+ data.Props["SiteURL"] = a.GetSiteURL()
+ data.Props["TelemetryIdHeader"] = T("api.templates.warn_metric_ack.body.diagnostic_id_header")
+ data.Props["TelemetryIdValue"] = a.TelemetryId()
+ data.Props["Footer"] = T("api.templates.warn_metric_ack.footer")
warnMetricStatus, warnMetricDisplayTexts := a.getWarnMetricStatusAndDisplayTextsForId(warnMetricId, T, false)
if warnMetricStatus == nil {
@@ -493,10 +489,16 @@ func (a *App) NotifyAndSetWarnMetricAck(warnMetricId string, sender *model.User,
}
subject := T("api.templates.warn_metric_ack.subject")
- bodyPage.Props["Title"] = warnMetricDisplayTexts.EmailBody
+ data.Props["Title"] = warnMetricDisplayTexts.EmailBody
mailConfig := a.Srv().MailServiceConfig()
- if err := mailservice.SendMailUsingConfig(model.MM_SUPPORT_ADVISOR_ADDRESS, subject, bodyPage.Render(), mailConfig, false, sender.Email); err != nil {
+
+ body, err := a.Srv().TemplatesContainer().RenderToString("warn_metric_ack", data)
+ if err != nil {
+ return model.NewAppError("NotifyAndSetWarnMetricAck", "api.email.send_warn_metric_ack.failure.app_error", map[string]interface{}{"Error": err.Error()}, "", http.StatusInternalServerError)
+ }
+
+ if err := mailservice.SendMailUsingConfig(model.MM_SUPPORT_ADVISOR_ADDRESS, subject, body, mailConfig, false, sender.Email); err != nil {
return model.NewAppError("NotifyAndSetWarnMetricAck", "api.email.send_warn_metric_ack.failure.app_error", map[string]interface{}{"Error": err.Error()}, "", http.StatusInternalServerError)
}
}
diff --git a/app/email.go b/app/email.go
index 204463f0ae..6fdc2a9f25 100644
--- a/app/email.go
+++ b/app/email.go
@@ -7,6 +7,7 @@ import (
"bytes"
"encoding/json"
"fmt"
+ "html/template"
"io"
"net/http"
"net/url"
@@ -22,7 +23,7 @@ import (
"github.com/mattermost/mattermost-server/v5/services/mailservice"
"github.com/mattermost/mattermost-server/v5/shared/i18n"
"github.com/mattermost/mattermost-server/v5/shared/mlog"
- "github.com/mattermost/mattermost-server/v5/utils"
+ "github.com/mattermost/mattermost-server/v5/shared/templates"
)
const (
@@ -94,14 +95,19 @@ func (es *EmailService) sendChangeUsernameEmail(newUsername, email, locale, site
map[string]interface{}{"SiteName": es.srv.Config().TeamSettings.SiteName,
"TeamDisplayName": es.srv.Config().TeamSettings.SiteName})
- bodyPage := es.newEmailTemplate("email_change_body", locale)
- bodyPage.Props["SiteURL"] = siteURL
- bodyPage.Props["Title"] = T("api.templates.username_change_body.title")
- bodyPage.Props["Info"] = T("api.templates.username_change_body.info",
+ data := es.newEmailTemplateData(locale)
+ data.Props["SiteURL"] = siteURL
+ data.Props["Title"] = T("api.templates.username_change_body.title")
+ data.Props["Info"] = T("api.templates.username_change_body.info",
map[string]interface{}{"TeamDisplayName": es.srv.Config().TeamSettings.SiteName, "NewUsername": newUsername})
- bodyPage.Props["Warning"] = T("api.templates.email_warning")
+ data.Props["Warning"] = T("api.templates.email_warning")
- if err := es.sendMail(email, subject, bodyPage.Render()); err != nil {
+ body, err := es.srv.TemplatesContainer().RenderToString("email_change_body", data)
+ if err != nil {
+ return model.NewAppError("sendChangeUsernameEmail", "api.user.send_email_change_username_and_forget.error", nil, err.Error(), http.StatusInternalServerError)
+ }
+
+ if err := es.sendMail(email, subject, body); err != nil {
return model.NewAppError("sendChangeUsernameEmail", "api.user.send_email_change_username_and_forget.error", nil, err.Error(), http.StatusInternalServerError)
}
@@ -117,15 +123,20 @@ func (es *EmailService) sendEmailChangeVerifyEmail(newUserEmail, locale, siteURL
map[string]interface{}{"SiteName": es.srv.Config().TeamSettings.SiteName,
"TeamDisplayName": es.srv.Config().TeamSettings.SiteName})
- bodyPage := es.newEmailTemplate("email_change_verify_body", locale)
- bodyPage.Props["SiteURL"] = siteURL
- bodyPage.Props["Title"] = T("api.templates.email_change_verify_body.title")
- bodyPage.Props["Info"] = T("api.templates.email_change_verify_body.info",
+ data := es.newEmailTemplateData(locale)
+ data.Props["SiteURL"] = siteURL
+ data.Props["Title"] = T("api.templates.email_change_verify_body.title")
+ data.Props["Info"] = T("api.templates.email_change_verify_body.info",
map[string]interface{}{"TeamDisplayName": es.srv.Config().TeamSettings.SiteName})
- bodyPage.Props["VerifyUrl"] = link
- bodyPage.Props["VerifyButton"] = T("api.templates.email_change_verify_body.button")
+ data.Props["VerifyUrl"] = link
+ data.Props["VerifyButton"] = T("api.templates.email_change_verify_body.button")
- if err := es.sendMail(newUserEmail, subject, bodyPage.Render()); err != nil {
+ body, err := es.srv.TemplatesContainer().RenderToString("email_change_verify_body", data)
+ if err != nil {
+ return model.NewAppError("sendEmailChangeVerifyEmail", "api.user.send_email_change_verify_email_and_forget.error", nil, err.Error(), http.StatusInternalServerError)
+ }
+
+ if err := es.sendMail(newUserEmail, subject, body); err != nil {
return model.NewAppError("sendEmailChangeVerifyEmail", "api.user.send_email_change_verify_email_and_forget.error", nil, err.Error(), http.StatusInternalServerError)
}
@@ -139,14 +150,19 @@ func (es *EmailService) sendEmailChangeEmail(oldEmail, newEmail, locale, siteURL
map[string]interface{}{"SiteName": es.srv.Config().TeamSettings.SiteName,
"TeamDisplayName": es.srv.Config().TeamSettings.SiteName})
- bodyPage := es.newEmailTemplate("email_change_body", locale)
- bodyPage.Props["SiteURL"] = siteURL
- bodyPage.Props["Title"] = T("api.templates.email_change_body.title")
- bodyPage.Props["Info"] = T("api.templates.email_change_body.info",
+ data := es.newEmailTemplateData(locale)
+ data.Props["SiteURL"] = siteURL
+ data.Props["Title"] = T("api.templates.email_change_body.title")
+ data.Props["Info"] = T("api.templates.email_change_body.info",
map[string]interface{}{"TeamDisplayName": es.srv.Config().TeamSettings.SiteName, "NewEmail": newEmail})
- bodyPage.Props["Warning"] = T("api.templates.email_warning")
+ data.Props["Warning"] = T("api.templates.email_warning")
- if err := es.sendMail(oldEmail, subject, bodyPage.Render()); err != nil {
+ body, err := es.srv.TemplatesContainer().RenderToString("email_change_body", data)
+ if err != nil {
+ return model.NewAppError("sendEmailChangeEmail", "api.user.send_email_change_email_and_forget.error", nil, err.Error(), http.StatusInternalServerError)
+ }
+
+ if err := es.sendMail(oldEmail, subject, body); err != nil {
return model.NewAppError("sendEmailChangeEmail", "api.user.send_email_change_email_and_forget.error", nil, err.Error(), http.StatusInternalServerError)
}
@@ -166,20 +182,25 @@ func (es *EmailService) sendVerifyEmail(userEmail, locale, siteURL, token, redir
subject := T("api.templates.verify_subject",
map[string]interface{}{"SiteName": es.srv.Config().TeamSettings.SiteName})
- bodyPage := es.newEmailTemplate("verify_body", locale)
- bodyPage.Props["SiteURL"] = siteURL
- bodyPage.Props["Title"] = T("api.templates.verify_body.title")
- bodyPage.Props["SubTitle1"] = T("api.templates.verify_body.subTitle1")
- bodyPage.Props["ServerURL"] = T("api.templates.verify_body.serverURL", map[string]interface{}{"ServerURL": serverURL})
- bodyPage.Props["SubTitle2"] = T("api.templates.verify_body.subTitle2")
- bodyPage.Props["ButtonURL"] = link
- bodyPage.Props["Button"] = T("api.templates.verify_body.button")
- bodyPage.Props["Info"] = T("api.templates.verify_body.info")
- bodyPage.Props["Info1"] = T("api.templates.verify_body.info1")
- bodyPage.Props["QuestionTitle"] = T("api.templates.questions_footer.title")
- bodyPage.Props["QuestionInfo"] = T("api.templates.questions_footer.info")
+ data := es.newEmailTemplateData(locale)
+ data.Props["SiteURL"] = siteURL
+ data.Props["Title"] = T("api.templates.verify_body.title")
+ data.Props["SubTitle1"] = T("api.templates.verify_body.subTitle1")
+ data.Props["ServerURL"] = T("api.templates.verify_body.serverURL", map[string]interface{}{"ServerURL": serverURL})
+ data.Props["SubTitle2"] = T("api.templates.verify_body.subTitle2")
+ data.Props["ButtonURL"] = link
+ data.Props["Button"] = T("api.templates.verify_body.button")
+ data.Props["Info"] = T("api.templates.verify_body.info")
+ data.Props["Info1"] = T("api.templates.verify_body.info1")
+ data.Props["QuestionTitle"] = T("api.templates.questions_footer.title")
+ data.Props["QuestionInfo"] = T("api.templates.questions_footer.info")
- if err := es.sendMail(userEmail, subject, bodyPage.Render()); err != nil {
+ body, err := es.srv.TemplatesContainer().RenderToString("verify_body", data)
+ if err != nil {
+ return model.NewAppError("SendVerifyEmail", "api.user.send_verify_email_and_forget.failed.error", nil, err.Error(), http.StatusInternalServerError)
+ }
+
+ if err := es.sendMail(userEmail, subject, body); err != nil {
return model.NewAppError("SendVerifyEmail", "api.user.send_verify_email_and_forget.failed.error", nil, err.Error(), http.StatusInternalServerError)
}
@@ -192,14 +213,19 @@ func (es *EmailService) SendSignInChangeEmail(email, method, locale, siteURL str
subject := T("api.templates.signin_change_email.subject",
map[string]interface{}{"SiteName": es.srv.Config().TeamSettings.SiteName})
- bodyPage := es.newEmailTemplate("signin_change_body", locale)
- bodyPage.Props["SiteURL"] = siteURL
- bodyPage.Props["Title"] = T("api.templates.signin_change_email.body.title")
- bodyPage.Props["Info"] = T("api.templates.signin_change_email.body.info",
+ data := es.newEmailTemplateData(locale)
+ data.Props["SiteURL"] = siteURL
+ data.Props["Title"] = T("api.templates.signin_change_email.body.title")
+ data.Props["Info"] = T("api.templates.signin_change_email.body.info",
map[string]interface{}{"SiteName": es.srv.Config().TeamSettings.SiteName, "Method": method})
- bodyPage.Props["Warning"] = T("api.templates.email_warning")
+ data.Props["Warning"] = T("api.templates.email_warning")
- if err := es.sendMail(email, subject, bodyPage.Render()); err != nil {
+ body, err := es.srv.TemplatesContainer().RenderToString("signin_change_body", data)
+ if err != nil {
+ return model.NewAppError("SendSignInChangeEmail", "api.user.send_sign_in_change_email_and_forget.error", nil, err.Error(), http.StatusInternalServerError)
+ }
+
+ if err := es.sendMail(email, subject, body); err != nil {
return model.NewAppError("SendSignInChangeEmail", "api.user.send_sign_in_change_email_and_forget.error", nil, err.Error(), http.StatusInternalServerError)
}
@@ -222,22 +248,22 @@ func (es *EmailService) sendWelcomeEmail(userID string, email string, verified b
map[string]interface{}{"SiteName": es.srv.Config().TeamSettings.SiteName,
"ServerURL": serverURL})
- bodyPage := es.newEmailTemplate("welcome_body", locale)
- bodyPage.Props["SiteURL"] = siteURL
- bodyPage.Props["Title"] = T("api.templates.welcome_body.title")
- bodyPage.Props["SubTitle1"] = T("api.templates.welcome_body.subTitle1")
- bodyPage.Props["ServerURL"] = T("api.templates.welcome_body.serverURL", map[string]interface{}{"ServerURL": serverURL})
- bodyPage.Props["SubTitle2"] = T("api.templates.welcome_body.subTitle2")
- bodyPage.Props["Button"] = T("api.templates.welcome_body.button")
- bodyPage.Props["Info"] = T("api.templates.welcome_body.info")
- bodyPage.Props["Info1"] = T("api.templates.welcome_body.info1")
- bodyPage.Props["SiteURL"] = siteURL
+ data := es.newEmailTemplateData(locale)
+ data.Props["SiteURL"] = siteURL
+ data.Props["Title"] = T("api.templates.welcome_body.title")
+ data.Props["SubTitle1"] = T("api.templates.welcome_body.subTitle1")
+ data.Props["ServerURL"] = T("api.templates.welcome_body.serverURL", map[string]interface{}{"ServerURL": serverURL})
+ data.Props["SubTitle2"] = T("api.templates.welcome_body.subTitle2")
+ data.Props["Button"] = T("api.templates.welcome_body.button")
+ data.Props["Info"] = T("api.templates.welcome_body.info")
+ data.Props["Info1"] = T("api.templates.welcome_body.info1")
+ data.Props["SiteURL"] = siteURL
if *es.srv.Config().NativeAppSettings.AppDownloadLink != "" {
- bodyPage.Props["AppDownloadTitle"] = T("api.templates.welcome_body.app_download_title")
- bodyPage.Props["AppDownloadInfo"] = T("api.templates.welcome_body.app_download_info")
- bodyPage.Props["AppDownloadButton"] = T("api.templates.welcome_body.app_download_button")
- bodyPage.Props["AppDownloadLink"] = *es.srv.Config().NativeAppSettings.AppDownloadLink
+ data.Props["AppDownloadTitle"] = T("api.templates.welcome_body.app_download_title")
+ data.Props["AppDownloadInfo"] = T("api.templates.welcome_body.app_download_info")
+ data.Props["AppDownloadButton"] = T("api.templates.welcome_body.app_download_button")
+ data.Props["AppDownloadLink"] = *es.srv.Config().NativeAppSettings.AppDownloadLink
}
if !verified && *es.srv.Config().EmailSettings.RequireEmailVerification {
@@ -249,10 +275,15 @@ func (es *EmailService) sendWelcomeEmail(userID string, email string, verified b
if redirect != "" {
link += fmt.Sprintf("&redirect_to=%s", redirect)
}
- bodyPage.Props["ButtonURL"] = link
+ data.Props["ButtonURL"] = link
}
- if err := es.sendMail(email, subject, bodyPage.Render()); err != nil {
+ body, err := es.srv.TemplatesContainer().RenderToString("welcome_body", data)
+ if err != nil {
+ return model.NewAppError("sendWelcomeEmail", "api.user.send_welcome_email_and_forget.failed.error", nil, err.Error(), http.StatusInternalServerError)
+ }
+
+ if err := es.sendMail(email, subject, body); err != nil {
return model.NewAppError("sendWelcomeEmail", "api.user.send_welcome_email_and_forget.failed.error", nil, err.Error(), http.StatusInternalServerError)
}
@@ -266,30 +297,35 @@ func (es *EmailService) SendCloudWelcomeEmail(userEmail, locale, teamInviteID, w
workSpacePath := fmt.Sprintf("https://%s.cloud.mattermost.com", workSpaceName)
- bodyPage := es.newEmailTemplate("cloud_welcome_email", locale)
- bodyPage.Props["Title"] = T("api.templates.cloud_welcome_email.title", map[string]interface{}{"WorkSpace": workSpaceName})
- bodyPage.Props["SubTitle"] = T("api.templates.cloud_welcome_email.subtitle")
- bodyPage.Props["SubTitleInfo"] = T("api.templates.cloud_welcome_email.subtitle_info")
- bodyPage.Props["Info"] = T("api.templates.cloud_welcome_email.info")
- bodyPage.Props["Info2"] = T("api.templates.cloud_welcome_email.info2")
- bodyPage.Props["WorkSpacePath"] = workSpacePath
- bodyPage.Props["DNS"] = dns
- bodyPage.Props["InviteInfo"] = T("api.templates.cloud_welcome_email.invite_info")
- bodyPage.Props["InviteSubInfo"] = T("api.templates.cloud_welcome_email.invite_sub_info", map[string]interface{}{"WorkSpace": workSpaceName})
- bodyPage.Props["InviteSubInfoLink"] = fmt.Sprintf("%s/signup_user_complete/?id=%s", workSpacePath, teamInviteID)
- bodyPage.Props["AddAppsInfo"] = T("api.templates.cloud_welcome_email.add_apps_info")
- bodyPage.Props["AddAppsSubInfo"] = T("api.templates.cloud_welcome_email.add_apps_sub_info")
- bodyPage.Props["AppMarketPlace"] = T("api.templates.cloud_welcome_email.app_market_place")
- bodyPage.Props["AppMarketPlaceLink"] = "https://integrations.mattermost.com/"
- bodyPage.Props["DownloadMMInfo"] = T("api.templates.cloud_welcome_email.download_mm_info")
- bodyPage.Props["SignInSubInfo"] = T("api.templates.cloud_welcome_email.signin_sub_info")
- bodyPage.Props["MMApps"] = T("api.templates.cloud_welcome_email.mm_apps")
- bodyPage.Props["SignInSubInfo2"] = T("api.templates.cloud_welcome_email.signin_sub_info2")
- bodyPage.Props["DownloadMMAppsLink"] = "https://mattermost.com/download/"
- bodyPage.Props["Button"] = T("api.templates.cloud_welcome_email.button")
- bodyPage.Props["GettingStartedQuestions"] = T("api.templates.cloud_welcome_email.start_questions")
+ data := es.newEmailTemplateData(locale)
+ data.Props["Title"] = T("api.templates.cloud_welcome_email.title", map[string]interface{}{"WorkSpace": workSpaceName})
+ data.Props["SubTitle"] = T("api.templates.cloud_welcome_email.subtitle")
+ data.Props["SubTitleInfo"] = T("api.templates.cloud_welcome_email.subtitle_info")
+ data.Props["Info"] = T("api.templates.cloud_welcome_email.info")
+ data.Props["Info2"] = T("api.templates.cloud_welcome_email.info2")
+ data.Props["WorkSpacePath"] = workSpacePath
+ data.Props["DNS"] = dns
+ data.Props["InviteInfo"] = T("api.templates.cloud_welcome_email.invite_info")
+ data.Props["InviteSubInfo"] = T("api.templates.cloud_welcome_email.invite_sub_info", map[string]interface{}{"WorkSpace": workSpaceName})
+ data.Props["InviteSubInfoLink"] = fmt.Sprintf("%s/signup_user_complete/?id=%s", workSpacePath, teamInviteID)
+ data.Props["AddAppsInfo"] = T("api.templates.cloud_welcome_email.add_apps_info")
+ data.Props["AddAppsSubInfo"] = T("api.templates.cloud_welcome_email.add_apps_sub_info")
+ data.Props["AppMarketPlace"] = T("api.templates.cloud_welcome_email.app_market_place")
+ data.Props["AppMarketPlaceLink"] = "https://integrations.mattermost.com/"
+ data.Props["DownloadMMInfo"] = T("api.templates.cloud_welcome_email.download_mm_info")
+ data.Props["SignInSubInfo"] = T("api.templates.cloud_welcome_email.signin_sub_info")
+ data.Props["MMApps"] = T("api.templates.cloud_welcome_email.mm_apps")
+ data.Props["SignInSubInfo2"] = T("api.templates.cloud_welcome_email.signin_sub_info2")
+ data.Props["DownloadMMAppsLink"] = "https://mattermost.com/download/"
+ data.Props["Button"] = T("api.templates.cloud_welcome_email.button")
+ data.Props["GettingStartedQuestions"] = T("api.templates.cloud_welcome_email.start_questions")
- if err := es.sendMail(userEmail, subject, bodyPage.Render()); err != nil {
+ body, err := es.srv.TemplatesContainer().RenderToString("cloud_welcome_email", data)
+ if err != nil {
+ return model.NewAppError("SendCloudWelcomeEmail", "api.user.send_cloud_welcome_email.error", nil, err.Error(), http.StatusInternalServerError)
+ }
+
+ if err := es.sendMail(userEmail, subject, body); err != nil {
return model.NewAppError("SendCloudWelcomeEmail", "api.user.send_cloud_welcome_email.error", nil, err.Error(), http.StatusInternalServerError)
}
@@ -303,14 +339,19 @@ func (es *EmailService) sendPasswordChangeEmail(email, method, locale, siteURL s
map[string]interface{}{"SiteName": es.srv.Config().TeamSettings.SiteName,
"TeamDisplayName": es.srv.Config().TeamSettings.SiteName})
- bodyPage := es.newEmailTemplate("password_change_body", locale)
- bodyPage.Props["SiteURL"] = siteURL
- bodyPage.Props["Title"] = T("api.templates.password_change_body.title")
- bodyPage.Props["Info"] = T("api.templates.password_change_body.info",
+ data := es.newEmailTemplateData(locale)
+ data.Props["SiteURL"] = siteURL
+ data.Props["Title"] = T("api.templates.password_change_body.title")
+ data.Props["Info"] = T("api.templates.password_change_body.info",
map[string]interface{}{"TeamDisplayName": es.srv.Config().TeamSettings.SiteName, "TeamURL": siteURL, "Method": method})
- bodyPage.Props["Warning"] = T("api.templates.email_warning")
+ data.Props["Warning"] = T("api.templates.email_warning")
- if err := es.sendMail(email, subject, bodyPage.Render()); err != nil {
+ body, err := es.srv.TemplatesContainer().RenderToString("password_change_body", data)
+ if err != nil {
+ return model.NewAppError("sendPasswordChangeEmail", "api.user.send_password_change_email_and_forget.error", nil, err.Error(), http.StatusInternalServerError)
+ }
+
+ if err := es.sendMail(email, subject, body); err != nil {
return model.NewAppError("sendPasswordChangeEmail", "api.user.send_password_change_email_and_forget.error", nil, err.Error(), http.StatusInternalServerError)
}
@@ -323,14 +364,19 @@ func (es *EmailService) sendUserAccessTokenAddedEmail(email, locale, siteURL str
subject := T("api.templates.user_access_token_subject",
map[string]interface{}{"SiteName": es.srv.Config().TeamSettings.SiteName})
- bodyPage := es.newEmailTemplate("password_change_body", locale)
- bodyPage.Props["SiteURL"] = siteURL
- bodyPage.Props["Title"] = T("api.templates.user_access_token_body.title")
- bodyPage.Props["Info"] = T("api.templates.user_access_token_body.info",
+ data := es.newEmailTemplateData(locale)
+ data.Props["SiteURL"] = siteURL
+ data.Props["Title"] = T("api.templates.user_access_token_body.title")
+ data.Props["Info"] = T("api.templates.user_access_token_body.info",
map[string]interface{}{"SiteName": es.srv.Config().TeamSettings.SiteName, "SiteURL": siteURL})
- bodyPage.Props["Warning"] = T("api.templates.email_warning")
+ data.Props["Warning"] = T("api.templates.email_warning")
- if err := es.sendMail(email, subject, bodyPage.Render()); err != nil {
+ body, err := es.srv.TemplatesContainer().RenderToString("password_change_body", data)
+ if err != nil {
+ return model.NewAppError("sendUserAccessTokenAddedEmail", "api.user.send_user_access_token.error", nil, err.Error(), http.StatusInternalServerError)
+ }
+
+ if err := es.sendMail(email, subject, body); err != nil {
return model.NewAppError("sendUserAccessTokenAddedEmail", "api.user.send_user_access_token.error", nil, err.Error(), http.StatusInternalServerError)
}
@@ -345,17 +391,22 @@ func (es *EmailService) SendPasswordResetEmail(email string, token *model.Token,
subject := T("api.templates.reset_subject",
map[string]interface{}{"SiteName": es.srv.Config().TeamSettings.SiteName})
- bodyPage := es.newEmailTemplate("reset_body", locale)
- bodyPage.Props["SiteURL"] = siteURL
- bodyPage.Props["Title"] = T("api.templates.reset_body.title")
- bodyPage.Props["SubTitle"] = T("api.templates.reset_body.subTitle")
- bodyPage.Props["Info"] = T("api.templates.reset_body.info")
- bodyPage.Props["ButtonURL"] = link
- bodyPage.Props["Button"] = T("api.templates.reset_body.button")
- bodyPage.Props["QuestionTitle"] = T("api.templates.questions_footer.title")
- bodyPage.Props["QuestionInfo"] = T("api.templates.questions_footer.info")
+ data := es.newEmailTemplateData(locale)
+ data.Props["SiteURL"] = siteURL
+ data.Props["Title"] = T("api.templates.reset_body.title")
+ data.Props["SubTitle"] = T("api.templates.reset_body.subTitle")
+ data.Props["Info"] = T("api.templates.reset_body.info")
+ data.Props["ButtonURL"] = link
+ data.Props["Button"] = T("api.templates.reset_body.button")
+ data.Props["QuestionTitle"] = T("api.templates.questions_footer.title")
+ data.Props["QuestionInfo"] = T("api.templates.questions_footer.info")
- if err := es.sendMail(email, subject, bodyPage.Render()); err != nil {
+ body, err := es.srv.TemplatesContainer().RenderToString("reset_body", data)
+ if err != nil {
+ return false, model.NewAppError("SendPasswordReset", "api.user.send_password_reset.send.app_error", nil, "err="+err.Error(), http.StatusInternalServerError)
+ }
+
+ if err := es.sendMail(email, subject, body); err != nil {
return false, model.NewAppError("SendPasswordReset", "api.user.send_password_reset.send.app_error", nil, "err="+err.Error(), http.StatusInternalServerError)
}
@@ -368,19 +419,24 @@ func (es *EmailService) sendMfaChangeEmail(email string, activated bool, locale,
subject := T("api.templates.mfa_change_subject",
map[string]interface{}{"SiteName": es.srv.Config().TeamSettings.SiteName})
- bodyPage := es.newEmailTemplate("mfa_change_body", locale)
- bodyPage.Props["SiteURL"] = siteURL
+ data := es.newEmailTemplateData(locale)
+ data.Props["SiteURL"] = siteURL
if activated {
- bodyPage.Props["Info"] = T("api.templates.mfa_activated_body.info", map[string]interface{}{"SiteURL": siteURL})
- bodyPage.Props["Title"] = T("api.templates.mfa_activated_body.title")
+ data.Props["Info"] = T("api.templates.mfa_activated_body.info", map[string]interface{}{"SiteURL": siteURL})
+ data.Props["Title"] = T("api.templates.mfa_activated_body.title")
} else {
- bodyPage.Props["Info"] = T("api.templates.mfa_deactivated_body.info", map[string]interface{}{"SiteURL": siteURL})
- bodyPage.Props["Title"] = T("api.templates.mfa_deactivated_body.title")
+ data.Props["Info"] = T("api.templates.mfa_deactivated_body.info", map[string]interface{}{"SiteURL": siteURL})
+ data.Props["Title"] = T("api.templates.mfa_deactivated_body.title")
}
- bodyPage.Props["Warning"] = T("api.templates.email_warning")
+ data.Props["Warning"] = T("api.templates.email_warning")
- if err := es.sendMail(email, subject, bodyPage.Render()); err != nil {
+ body, err := es.srv.TemplatesContainer().RenderToString("mfa_change_body", data)
+ if err != nil {
+ return model.NewAppError("SendMfaChangeEmail", "api.user.send_mfa_change_email.error", nil, err.Error(), http.StatusInternalServerError)
+ }
+
+ if err := es.sendMail(email, subject, body); err != nil {
return model.NewAppError("SendMfaChangeEmail", "api.user.send_mfa_change_email.error", nil, err.Error(), http.StatusInternalServerError)
}
@@ -411,34 +467,39 @@ func (es *EmailService) SendInviteEmails(team *model.Team, senderName string, se
"TeamDisplayName": team.DisplayName,
"SiteName": es.srv.Config().TeamSettings.SiteName})
- bodyPage := es.newEmailTemplate("invite_body", "")
- bodyPage.Props["SiteURL"] = siteURL
- bodyPage.Props["Title"] = i18n.T("api.templates.invite_body.title", map[string]interface{}{"SenderName": senderName, "TeamDisplayName": team.DisplayName})
- bodyPage.Props["SubTitle"] = i18n.T("api.templates.invite_body.subTitle")
- bodyPage.Props["Button"] = i18n.T("api.templates.invite_body.button")
- bodyPage.Props["SenderName"] = senderName
- bodyPage.Props["InviteFooterTitle"] = i18n.T("api.templates.invite_body_footer.title")
- bodyPage.Props["InviteFooterInfo"] = i18n.T("api.templates.invite_body_footer.info")
- bodyPage.Props["InviteFooterLearnMore"] = i18n.T("api.templates.invite_body_footer.learn_more")
+ data := es.newEmailTemplateData("")
+ data.Props["SiteURL"] = siteURL
+ data.Props["Title"] = i18n.T("api.templates.invite_body.title", map[string]interface{}{"SenderName": senderName, "TeamDisplayName": team.DisplayName})
+ data.Props["SubTitle"] = i18n.T("api.templates.invite_body.subTitle")
+ data.Props["Button"] = i18n.T("api.templates.invite_body.button")
+ data.Props["SenderName"] = senderName
+ data.Props["InviteFooterTitle"] = i18n.T("api.templates.invite_body_footer.title")
+ data.Props["InviteFooterInfo"] = i18n.T("api.templates.invite_body_footer.info")
+ data.Props["InviteFooterLearnMore"] = i18n.T("api.templates.invite_body_footer.learn_more")
token := model.NewToken(
TokenTypeTeamInvitation,
model.MapToJson(map[string]string{"teamId": team.Id, "email": invite}),
)
- props := make(map[string]string)
- props["email"] = invite
- props["display_name"] = team.DisplayName
- props["name"] = team.Name
- data := model.MapToJson(props)
+ tokenProps := make(map[string]string)
+ tokenProps["email"] = invite
+ tokenProps["display_name"] = team.DisplayName
+ tokenProps["name"] = team.Name
+ tokenData := model.MapToJson(tokenProps)
if err := es.srv.Store.Token().Save(token); err != nil {
mlog.Error("Failed to send invite email successfully ", mlog.Err(err))
continue
}
- bodyPage.Props["ButtonURL"] = fmt.Sprintf("%s/signup_user_complete/?d=%s&t=%s", siteURL, url.QueryEscape(data), url.QueryEscape(token.Token))
+ data.Props["ButtonURL"] = fmt.Sprintf("%s/signup_user_complete/?d=%s&t=%s", siteURL, url.QueryEscape(tokenData), url.QueryEscape(token.Token))
- if err := es.sendMail(invite, subject, bodyPage.Render()); err != nil {
+ body, err := es.srv.TemplatesContainer().RenderToString("invite_body", data)
+ if err != nil {
+ mlog.Error("Failed to send invite email successfully ", mlog.Err(err))
+ }
+
+ if err := es.sendMail(invite, subject, body); err != nil {
mlog.Error("Failed to send invite email successfully ", mlog.Err(err))
}
}
@@ -470,19 +531,19 @@ func (es *EmailService) sendGuestInviteEmails(team *model.Team, channels []*mode
"TeamDisplayName": team.DisplayName,
"SiteName": es.srv.Config().TeamSettings.SiteName})
- bodyPage := es.newEmailTemplate("invite_body", "")
- bodyPage.Props["SiteURL"] = siteURL
- bodyPage.Props["Title"] = i18n.T("api.templates.invite_body.title", map[string]interface{}{"SenderName": senderName, "TeamDisplayName": team.DisplayName})
- bodyPage.Props["SubTitle"] = i18n.T("api.templates.invite_body_guest.subTitle")
- bodyPage.Props["Button"] = i18n.T("api.templates.invite_body.button")
- bodyPage.Props["SenderName"] = senderName
- bodyPage.Props["Message"] = ""
+ data := es.newEmailTemplateData("")
+ data.Props["SiteURL"] = siteURL
+ data.Props["Title"] = i18n.T("api.templates.invite_body.title", map[string]interface{}{"SenderName": senderName, "TeamDisplayName": team.DisplayName})
+ data.Props["SubTitle"] = i18n.T("api.templates.invite_body_guest.subTitle")
+ data.Props["Button"] = i18n.T("api.templates.invite_body.button")
+ data.Props["SenderName"] = senderName
+ data.Props["Message"] = ""
if message != "" {
- bodyPage.Props["Message"] = message
+ data.Props["Message"] = message
}
- bodyPage.Props["InviteFooterTitle"] = i18n.T("api.templates.invite_body_footer.title")
- bodyPage.Props["InviteFooterInfo"] = i18n.T("api.templates.invite_body_footer.info")
- bodyPage.Props["InviteFooterLearnMore"] = i18n.T("api.templates.invite_body_footer.learn_more")
+ data.Props["InviteFooterTitle"] = i18n.T("api.templates.invite_body_footer.title")
+ data.Props["InviteFooterInfo"] = i18n.T("api.templates.invite_body_footer.info")
+ data.Props["InviteFooterLearnMore"] = i18n.T("api.templates.invite_body_footer.learn_more")
channelIDs := []string{}
for _, channel := range channels {
@@ -499,20 +560,20 @@ func (es *EmailService) sendGuestInviteEmails(team *model.Team, channels []*mode
}),
)
- props := make(map[string]string)
- props["email"] = invite
- props["display_name"] = team.DisplayName
- props["name"] = team.Name
- data := model.MapToJson(props)
+ tokenProps := make(map[string]string)
+ tokenProps["email"] = invite
+ tokenProps["display_name"] = team.DisplayName
+ tokenProps["name"] = team.Name
+ tokenData := model.MapToJson(tokenProps)
if err := es.srv.Store.Token().Save(token); err != nil {
mlog.Error("Failed to send invite email successfully ", mlog.Err(err))
continue
}
- bodyPage.Props["ButtonURL"] = fmt.Sprintf("%s/signup_user_complete/?d=%s&t=%s", siteURL, url.QueryEscape(data), url.QueryEscape(token.Token))
+ data.Props["ButtonURL"] = fmt.Sprintf("%s/signup_user_complete/?d=%s&t=%s", siteURL, url.QueryEscape(tokenData), url.QueryEscape(token.Token))
if !*es.srv.Config().EmailSettings.SendEmailNotifications {
- mlog.Info("sending invitation ", mlog.String("to", invite), mlog.String("link", bodyPage.Props["Link"].(string)))
+ mlog.Info("sending invitation ", mlog.String("to", invite), mlog.String("link", data.Props["ButtomURL"].(string)))
}
embeddedFiles := make(map[string]io.Reader)
@@ -524,7 +585,12 @@ func (es *EmailService) sendGuestInviteEmails(team *model.Team, channels []*mode
}
}
- if nErr := es.sendMailWithEmbeddedFiles(invite, subject, bodyPage.Render(), embeddedFiles); nErr != nil {
+ body, err := es.srv.TemplatesContainer().RenderToString("invite_body", data)
+ if err != nil {
+ mlog.Error("Failed to send invite email successfully", mlog.Err(err))
+ }
+
+ if nErr := es.sendMailWithEmbeddedFiles(invite, subject, body, embeddedFiles); nErr != nil {
mlog.Error("Failed to send invite email successfully", mlog.Err(nErr))
}
}
@@ -532,32 +598,32 @@ func (es *EmailService) sendGuestInviteEmails(team *model.Team, channels []*mode
return nil
}
-func (es *EmailService) newEmailTemplate(name, locale string) *utils.HTMLTemplate {
- t := utils.NewHTMLTemplate(es.srv.HTMLTemplates(), name)
-
+func (es *EmailService) newEmailTemplateData(locale string) templates.Data {
var localT i18n.TranslateFunc
if locale != "" {
localT = i18n.GetUserTranslations(locale)
} else {
localT = i18n.T
}
-
- t.Props["Footer"] = localT("api.templates.email_footer")
- t.Props["FooterV2"] = localT("api.templates.email_footer_v2")
+ organization := ""
if *es.srv.Config().EmailSettings.FeedbackOrganization != "" {
- t.Props["Organization"] = localT("api.templates.email_organization") + *es.srv.Config().EmailSettings.FeedbackOrganization
- } else {
- t.Props["Organization"] = ""
+ organization = localT("api.templates.email_organization") + *es.srv.Config().EmailSettings.FeedbackOrganization
}
- t.Props["EmailInfo1"] = localT("api.templates.email_info1")
- t.Props["EmailInfo2"] = localT("api.templates.email_info2")
- t.Props["EmailInfo3"] = localT("api.templates.email_info3",
- map[string]interface{}{"SiteName": es.srv.Config().TeamSettings.SiteName})
- t.Props["SupportEmail"] = *es.srv.Config().SupportSettings.SupportEmail
-
- return t
+ return templates.Data{
+ Props: map[string]interface{}{
+ "EmailInfo1": localT("api.templates.email_info1"),
+ "EmailInfo2": localT("api.templates.email_info2"),
+ "EmailInfo3": localT("api.templates.email_info3",
+ map[string]interface{}{"SiteName": es.srv.Config().TeamSettings.SiteName}),
+ "SupportEmail": *es.srv.Config().SupportSettings.SupportEmail,
+ "Footer": localT("api.templates.email_footer"),
+ "FooterV2": localT("api.templates.email_footer_v2"),
+ "Organization": organization,
+ },
+ HTML: map[string]template.HTML{},
+ }
}
func (es *EmailService) SendDeactivateAccountEmail(email string, locale, siteURL string) *model.AppError {
@@ -569,14 +635,19 @@ func (es *EmailService) SendDeactivateAccountEmail(email string, locale, siteURL
map[string]interface{}{"SiteName": es.srv.Config().TeamSettings.SiteName,
"ServerURL": serverURL})
- bodyPage := es.newEmailTemplate("deactivate_body", locale)
- bodyPage.Props["SiteURL"] = siteURL
- bodyPage.Props["Title"] = T("api.templates.deactivate_body.title", map[string]interface{}{"ServerURL": serverURL})
- bodyPage.Props["Info"] = T("api.templates.deactivate_body.info",
+ data := es.newEmailTemplateData(locale)
+ data.Props["SiteURL"] = siteURL
+ data.Props["Title"] = T("api.templates.deactivate_body.title", map[string]interface{}{"ServerURL": serverURL})
+ data.Props["Info"] = T("api.templates.deactivate_body.info",
map[string]interface{}{"SiteURL": siteURL})
- bodyPage.Props["Warning"] = T("api.templates.deactivate_body.warning")
+ data.Props["Warning"] = T("api.templates.deactivate_body.warning")
- if err := es.sendMail(email, subject, bodyPage.Render()); err != nil {
+ body, err := es.srv.TemplatesContainer().RenderToString("deactivate_body", data)
+ if err != nil {
+ return model.NewAppError("SendDeactivateEmail", "api.user.send_deactivate_email_and_forget.failed.error", nil, err.Error(), http.StatusInternalServerError)
+ }
+
+ if err := es.sendMail(email, subject, body); err != nil {
return model.NewAppError("SendDeactivateEmail", "api.user.send_deactivate_email_and_forget.failed.error", nil, err.Error(), http.StatusInternalServerError)
}
@@ -595,13 +666,18 @@ func (es *EmailService) SendRemoveExpiredLicenseEmail(email string, locale, site
subject := T("api.templates.remove_expired_license.subject",
map[string]interface{}{"SiteName": es.srv.Config().TeamSettings.SiteName})
- bodyPage := es.newEmailTemplate("remove_expired_license", locale)
- bodyPage.Props["SiteURL"] = siteURL
- bodyPage.Props["Title"] = T("api.templates.remove_expired_license.body.title")
- bodyPage.Props["Link"] = renewalLink
- bodyPage.Props["LinkButton"] = T("api.templates.remove_expired_license.body.renew_button")
+ data := es.newEmailTemplateData(locale)
+ data.Props["SiteURL"] = siteURL
+ data.Props["Title"] = T("api.templates.remove_expired_license.body.title")
+ data.Props["Link"] = renewalLink
+ data.Props["LinkButton"] = T("api.templates.remove_expired_license.body.renew_button")
- if err := es.sendMail(email, subject, bodyPage.Render()); err != nil {
+ body, nErr := es.srv.TemplatesContainer().RenderToString("remove_expired_license", data)
+ if nErr != nil {
+ return model.NewAppError("SendRemoveExpiredLicenseEmail", "api.license.remove_expired_license.failed.error", nil, nErr.Error(), http.StatusInternalServerError)
+ }
+
+ if err := es.sendMail(email, subject, body); err != nil {
return model.NewAppError("SendRemoveExpiredLicenseEmail", "api.license.remove_expired_license.failed.error", nil, err.Error(), http.StatusInternalServerError)
}
@@ -667,17 +743,22 @@ func (es *EmailService) SendAtUserLimitWarningEmail(email string, locale string,
subject := T("api.templates.at_limit_subject")
- bodyPage := es.newEmailTemplate("reached_user_limit_body", locale)
- bodyPage.Props["SiteURL"] = siteURL
- bodyPage.Props["Title"] = T("api.templates.at_limit_title")
- bodyPage.Props["Info1"] = T("api.templates.at_limit_info1")
- bodyPage.Props["Info2"] = T("api.templates.at_limit_info2")
- bodyPage.Props["Button"] = T("api.templates.upgrade_mattermost_cloud")
- bodyPage.Props["EmailUs"] = T("api.templates.email_us_anytime_at")
+ data := es.newEmailTemplateData(locale)
+ data.Props["SiteURL"] = siteURL
+ data.Props["Title"] = T("api.templates.at_limit_title")
+ data.Props["Info1"] = T("api.templates.at_limit_info1")
+ data.Props["Info2"] = T("api.templates.at_limit_info2")
+ data.Props["Button"] = T("api.templates.upgrade_mattermost_cloud")
+ data.Props["EmailUs"] = T("api.templates.email_us_anytime_at")
- bodyPage.Props["Footer"] = T("api.templates.copyright")
+ data.Props["Footer"] = T("api.templates.copyright")
- if err := es.sendMail(email, subject, bodyPage.Render()); err != nil {
+ body, err := es.srv.TemplatesContainer().RenderToString("reached_user_limit_body", data)
+ if err != nil {
+ return false, model.NewAppError("SendAtUserLimitWarningEmail", "api.user.send_password_reset.send.app_error", nil, "err="+err.Error(), http.StatusInternalServerError)
+ }
+
+ if err := es.sendMail(email, subject, body); err != nil {
return false, model.NewAppError("SendAtUserLimitWarningEmail", "api.user.send_password_reset.send.app_error", nil, "err="+err.Error(), http.StatusInternalServerError)
}
@@ -688,25 +769,30 @@ func (es *EmailService) SendAtUserLimitWarningEmail(email string, locale string,
func (es *EmailService) SendUpgradeEmail(user, email, locale, siteURL, action string) (bool, *model.AppError) {
T := i18n.GetUserTranslations(locale)
- bodyPage := es.newEmailTemplate("cloud_upgrade_request_email", locale)
+ subject := T("api.templates.upgrade_request_subject")
+
+ data := es.newEmailTemplateData(locale)
+ data.Props["Info5"] = T("api.templates.at_limit_info5")
+ data.Props["BillingPath"] = "admin_console/billing/subscription"
+ data.Props["SiteURL"] = siteURL
+ data.Props["Button"] = T("api.templates.upgrade_mattermost_cloud")
+ data.Props["EmailUs"] = T("api.templates.email_us_anytime_at")
+ data.Props["Footer"] = T("api.templates.copyright")
if action == model.InviteLimitation {
- bodyPage.Props["Title"] = T("api.templates.upgrade_request_title", map[string]interface{}{"UserName": user})
- bodyPage.Props["Info4"] = T("api.templates.upgrade_request_info4")
+ data.Props["Title"] = T("api.templates.upgrade_request_title", map[string]interface{}{"UserName": user})
+ data.Props["Info4"] = T("api.templates.upgrade_request_info4")
} else {
- bodyPage.Props["Title"] = T("api.templates.upgrade_request_title2")
- bodyPage.Props["Info4"] = T("api.templates.upgrade_request_info4_2")
+ data.Props["Title"] = T("api.templates.upgrade_request_title2")
+ data.Props["Info4"] = T("api.templates.upgrade_request_info4_2")
}
- subject := T("api.templates.upgrade_request_subject")
- bodyPage.Props["Info5"] = T("api.templates.at_limit_info5")
- bodyPage.Props["BillingPath"] = "admin_console/billing/subscription"
- bodyPage.Props["SiteURL"] = siteURL
- bodyPage.Props["Button"] = T("api.templates.upgrade_mattermost_cloud")
- bodyPage.Props["EmailUs"] = T("api.templates.email_us_anytime_at")
- bodyPage.Props["Footer"] = T("api.templates.copyright")
+ body, err := es.srv.TemplatesContainer().RenderToString("cloud_upgrade_request_email", data)
+ if err != nil {
+ return false, model.NewAppError("SendUpgradeEmail", "api.user.send_upgrade_request_email.error", nil, err.Error(), http.StatusInternalServerError)
+ }
- if err := es.sendMail(email, subject, bodyPage.Render()); err != nil {
+ if err := es.sendMail(email, subject, body); err != nil {
return false, model.NewAppError("SendUpgradeEmail", "api.user.send_upgrade_request_email.error", nil, err.Error(), http.StatusInternalServerError)
}
@@ -718,17 +804,22 @@ func (es *EmailService) SendOverUserLimitWarningEmail(email string, locale strin
subject := T("api.templates.over_limit_subject")
- bodyPage := es.newEmailTemplate("reached_user_limit_body", locale)
- bodyPage.Props["SiteURL"] = siteURL
- bodyPage.Props["Title"] = T("api.templates.over_limit_title")
- bodyPage.Props["Info1"] = T("api.templates.over_limit_info1")
- bodyPage.Props["Info2"] = T("api.templates.over_limit_info2")
- bodyPage.Props["Button"] = T("api.templates.upgrade_mattermost_cloud")
- bodyPage.Props["EmailUs"] = T("api.templates.email_us_anytime_at")
+ data := es.newEmailTemplateData(locale)
+ data.Props["SiteURL"] = siteURL
+ data.Props["Title"] = T("api.templates.over_limit_title")
+ data.Props["Info1"] = T("api.templates.over_limit_info1")
+ data.Props["Info2"] = T("api.templates.over_limit_info2")
+ data.Props["Button"] = T("api.templates.upgrade_mattermost_cloud")
+ data.Props["EmailUs"] = T("api.templates.email_us_anytime_at")
- bodyPage.Props["Footer"] = T("api.templates.copyright")
+ data.Props["Footer"] = T("api.templates.copyright")
- if err := es.sendMail(email, subject, bodyPage.Render()); err != nil {
+ body, err := es.srv.TemplatesContainer().RenderToString("reached_user_limit_body", data)
+ if err != nil {
+ return false, model.NewAppError("SendOverUserLimitWarningEmail", "api.user.send_password_reset.send.app_error", nil, "err="+err.Error(), http.StatusInternalServerError)
+ }
+
+ if err := es.sendMail(email, subject, body); err != nil {
return false, model.NewAppError("SendOverUserLimitWarningEmail", "api.user.send_password_reset.send.app_error", nil, "err="+err.Error(), http.StatusInternalServerError)
}
@@ -740,20 +831,25 @@ func (es *EmailService) SendOverUserLimitThirtyDayWarningEmail(email string, loc
subject := T("api.templates.over_limit_30_days_subject")
- bodyPage := es.newEmailTemplate("over_user_limit_30_days_body", locale)
- bodyPage.Props["SiteURL"] = siteURL
- bodyPage.Props["Title"] = T("api.templates.over_limit_30_days_title")
- bodyPage.Props["Info1"] = T("api.templates.over_limit_30_days_info1")
- bodyPage.Props["Info2"] = T("api.templates.over_limit_30_days_info2")
- bodyPage.Props["Info2Item1"] = T("api.templates.over_limit_30_days_info2_item1")
- bodyPage.Props["Info2Item2"] = T("api.templates.over_limit_30_days_info2_item2")
- bodyPage.Props["Info2Item3"] = T("api.templates.over_limit_30_days_info2_item3")
- bodyPage.Props["Button"] = T("api.templates.over_limit_fix_now")
- bodyPage.Props["EmailUs"] = T("api.templates.email_us_anytime_at")
+ data := es.newEmailTemplateData(locale)
+ data.Props["SiteURL"] = siteURL
+ data.Props["Title"] = T("api.templates.over_limit_30_days_title")
+ data.Props["Info1"] = T("api.templates.over_limit_30_days_info1")
+ data.Props["Info2"] = T("api.templates.over_limit_30_days_info2")
+ data.Props["Info2Item1"] = T("api.templates.over_limit_30_days_info2_item1")
+ data.Props["Info2Item2"] = T("api.templates.over_limit_30_days_info2_item2")
+ data.Props["Info2Item3"] = T("api.templates.over_limit_30_days_info2_item3")
+ data.Props["Button"] = T("api.templates.over_limit_fix_now")
+ data.Props["EmailUs"] = T("api.templates.email_us_anytime_at")
- bodyPage.Props["Footer"] = T("api.templates.copyright")
+ data.Props["Footer"] = T("api.templates.copyright")
- if err := es.sendMail(email, subject, bodyPage.Render()); err != nil {
+ body, err := es.srv.TemplatesContainer().RenderToString("over_user_limit_30_days_body", data)
+ if err != nil {
+ return false, model.NewAppError("SendOverUserLimitWarningEmail", "api.user.send_password_reset.send.app_error", nil, "err="+err.Error(), http.StatusInternalServerError)
+ }
+
+ if err := es.sendMail(email, subject, body); err != nil {
return false, model.NewAppError("SendOverUserLimitWarningEmail", "api.user.send_password_reset.send.app_error", nil, "err="+err.Error(), http.StatusInternalServerError)
}
@@ -765,19 +861,24 @@ func (es *EmailService) SendOverUserLimitNinetyDayWarningEmail(email string, loc
subject := T("api.templates.over_limit_90_days_subject")
- bodyPage := es.newEmailTemplate("over_user_limit_90_days_body", locale)
- bodyPage.Props["SiteURL"] = siteURL
- bodyPage.Props["Title"] = T("api.templates.over_limit_90_days_title")
- bodyPage.Props["Info1"] = T("api.templates.over_limit_90_days_info1", map[string]interface{}{"OverLimitDate": overLimitDate})
- bodyPage.Props["Info2"] = T("api.templates.over_limit_90_days_info2")
- bodyPage.Props["Info3"] = T("api.templates.over_limit_90_days_info3")
- bodyPage.Props["Info4"] = T("api.templates.over_limit_90_days_info4")
- bodyPage.Props["Button"] = T("api.templates.over_limit_fix_now")
- bodyPage.Props["EmailUs"] = T("api.templates.email_us_anytime_at")
+ data := es.newEmailTemplateData(locale)
+ data.Props["SiteURL"] = siteURL
+ data.Props["Title"] = T("api.templates.over_limit_90_days_title")
+ data.Props["Info1"] = T("api.templates.over_limit_90_days_info1", map[string]interface{}{"OverLimitDate": overLimitDate})
+ data.Props["Info2"] = T("api.templates.over_limit_90_days_info2")
+ data.Props["Info3"] = T("api.templates.over_limit_90_days_info3")
+ data.Props["Info4"] = T("api.templates.over_limit_90_days_info4")
+ data.Props["Button"] = T("api.templates.over_limit_fix_now")
+ data.Props["EmailUs"] = T("api.templates.email_us_anytime_at")
- bodyPage.Props["Footer"] = T("api.templates.copyright")
+ data.Props["Footer"] = T("api.templates.copyright")
- if err := es.sendMail(email, subject, bodyPage.Render()); err != nil {
+ body, err := es.srv.TemplatesContainer().RenderToString("over_user_limit_90_days_body", data)
+ if err != nil {
+ return false, model.NewAppError("SendOverUserLimitWarningEmail", "api.user.send_password_reset.send.app_error", nil, "err="+err.Error(), http.StatusInternalServerError)
+ }
+
+ if err := es.sendMail(email, subject, body); err != nil {
return false, model.NewAppError("SendOverUserLimitWarningEmail", "api.user.send_password_reset.send.app_error", nil, "err="+err.Error(), http.StatusInternalServerError)
}
@@ -789,17 +890,22 @@ func (es *EmailService) SendOverUserLimitWorkspaceSuspendedWarningEmail(email st
subject := T("api.templates.over_limit_suspended_subject")
- bodyPage := es.newEmailTemplate("over_user_limit_workspace_suspended_body", locale)
- bodyPage.Props["SiteURL"] = siteURL
- bodyPage.Props["Title"] = T("api.templates.over_limit_suspended_title")
- bodyPage.Props["Info1"] = T("api.templates.over_limit_suspended_info1")
- bodyPage.Props["Info2"] = T("api.templates.over_limit_suspended_info2")
- bodyPage.Props["Button"] = T("api.templates.over_limit_suspended_contact_support")
- bodyPage.Props["EmailUs"] = T("api.templates.email_us_anytime_at")
+ data := es.newEmailTemplateData(locale)
+ data.Props["SiteURL"] = siteURL
+ data.Props["Title"] = T("api.templates.over_limit_suspended_title")
+ data.Props["Info1"] = T("api.templates.over_limit_suspended_info1")
+ data.Props["Info2"] = T("api.templates.over_limit_suspended_info2")
+ data.Props["Button"] = T("api.templates.over_limit_suspended_contact_support")
+ data.Props["EmailUs"] = T("api.templates.email_us_anytime_at")
- bodyPage.Props["Footer"] = T("api.templates.copyright")
+ data.Props["Footer"] = T("api.templates.copyright")
- if err := es.sendMail(email, subject, bodyPage.Render()); err != nil {
+ body, err := es.srv.TemplatesContainer().RenderToString("over_user_limit_workspace_suspended_body", data)
+ if err != nil {
+ return false, model.NewAppError("SendOverUserLimitWarningEmail", "api.user.send_password_reset.send.app_error", nil, "err="+err.Error(), http.StatusInternalServerError)
+ }
+
+ if err := es.sendMail(email, subject, body); err != nil {
return false, model.NewAppError("SendOverUserLimitWarningEmail", "api.user.send_password_reset.send.app_error", nil, "err="+err.Error(), http.StatusInternalServerError)
}
@@ -811,16 +917,21 @@ func (es *EmailService) SendOverUserFourteenDayWarningEmail(email string, locale
subject := T("api.templates.over_limit_14_days_subject")
- bodyPage := es.newEmailTemplate("over_user_limit_7_days_body", locale)
- bodyPage.Props["SiteURL"] = siteURL
- bodyPage.Props["Title"] = T("api.templates.over_limit_14_days_title")
- bodyPage.Props["Info1"] = T("api.templates.over_limit_14_days_info1", map[string]interface{}{"OverLimitDate": overLimitDate})
- bodyPage.Props["Button"] = T("api.templates.over_limit_fix_now")
- bodyPage.Props["EmailUs"] = T("api.templates.email_us_anytime_at")
+ data := es.newEmailTemplateData(locale)
+ data.Props["SiteURL"] = siteURL
+ data.Props["Title"] = T("api.templates.over_limit_14_days_title")
+ data.Props["Info1"] = T("api.templates.over_limit_14_days_info1", map[string]interface{}{"OverLimitDate": overLimitDate})
+ data.Props["Button"] = T("api.templates.over_limit_fix_now")
+ data.Props["EmailUs"] = T("api.templates.email_us_anytime_at")
- bodyPage.Props["Footer"] = T("api.templates.copyright")
+ data.Props["Footer"] = T("api.templates.copyright")
- if err := es.sendMail(email, subject, bodyPage.Render()); err != nil {
+ body, err := es.srv.TemplatesContainer().RenderToString("over_user_limit_7_days_body", data)
+ if err != nil {
+ return false, model.NewAppError("SendOverUserLimitWarningEmail", "api.user.send_password_reset.send.app_error", nil, "err="+err.Error(), http.StatusInternalServerError)
+ }
+
+ if err := es.sendMail(email, subject, body); err != nil {
return false, model.NewAppError("SendOverUserLimitWarningEmail", "api.user.send_password_reset.send.app_error", nil, "err="+err.Error(), http.StatusInternalServerError)
}
@@ -832,16 +943,21 @@ func (es *EmailService) SendOverUserSevenDayWarningEmail(email string, locale st
subject := T("api.templates.over_limit_7_days_subject")
- bodyPage := es.newEmailTemplate("over_user_limit_7_days_body", locale)
- bodyPage.Props["SiteURL"] = siteURL
- bodyPage.Props["Title"] = T("api.templates.over_limit_7_days_title")
- bodyPage.Props["Info1"] = T("api.templates.over_limit_7_days_info1")
- bodyPage.Props["Button"] = T("api.templates.over_limit_fix_now")
- bodyPage.Props["EmailUs"] = T("api.templates.email_us_anytime_at")
+ data := es.newEmailTemplateData(locale)
+ data.Props["SiteURL"] = siteURL
+ data.Props["Title"] = T("api.templates.over_limit_7_days_title")
+ data.Props["Info1"] = T("api.templates.over_limit_7_days_info1")
+ data.Props["Button"] = T("api.templates.over_limit_fix_now")
+ data.Props["EmailUs"] = T("api.templates.email_us_anytime_at")
- bodyPage.Props["Footer"] = T("api.templates.copyright")
+ data.Props["Footer"] = T("api.templates.copyright")
- if err := es.sendMail(email, subject, bodyPage.Render()); err != nil {
+ body, err := es.srv.TemplatesContainer().RenderToString("over_user_limit_7_days_body", data)
+ if err != nil {
+ return false, model.NewAppError("SendOverUserLimitWarningEmail", "api.user.send_password_reset.send.app_error", nil, "err="+err.Error(), http.StatusInternalServerError)
+ }
+
+ if err := es.sendMail(email, subject, body); err != nil {
return false, model.NewAppError("SendOverUserLimitWarningEmail", "api.user.send_password_reset.send.app_error", nil, "err="+err.Error(), http.StatusInternalServerError)
}
@@ -852,15 +968,20 @@ func (es *EmailService) SendSuspensionEmailToSupport(email string, installationI
// Localization not needed
subject := fmt.Sprintf("Cloud Installation %s Scheduled Suspension", installationID)
- bodyPage := es.newEmailTemplate("over_user_limit_support_body", "en")
- bodyPage.Props["CustomerID"] = customerID
- bodyPage.Props["SiteURL"] = siteURL
- bodyPage.Props["SubscriptionID"] = subscriptionID
- bodyPage.Props["InstallationID"] = installationID
- bodyPage.Props["SuspensionDate"] = time.Now().AddDate(0, 0, 61).Format("2006-01-02")
- bodyPage.Props["UserCount"] = userCount
+ data := es.newEmailTemplateData("en")
+ data.Props["CustomerID"] = customerID
+ data.Props["SiteURL"] = siteURL
+ data.Props["SubscriptionID"] = subscriptionID
+ data.Props["InstallationID"] = installationID
+ data.Props["SuspensionDate"] = time.Now().AddDate(0, 0, 61).Format("2006-01-02")
+ data.Props["UserCount"] = userCount
- if err := es.sendMail(email, subject, bodyPage.Render()); err != nil {
+ body, err := es.srv.TemplatesContainer().RenderToString("over_user_limit_support_body", data)
+ if err != nil {
+ return false, model.NewAppError("SendOverUserLimitWarningEmail", "api.user.send_password_reset.send.app_error", nil, "err="+err.Error(), http.StatusInternalServerError)
+ }
+
+ if err := es.sendMail(email, subject, body); err != nil {
return false, model.NewAppError("SendOverUserLimitWarningEmail", "api.user.send_password_reset.send.app_error", nil, "err="+err.Error(), http.StatusInternalServerError)
}
@@ -872,20 +993,25 @@ func (es *EmailService) SendPaymentFailedEmail(email string, locale string, fail
subject := T("api.templates.payment_failed.subject")
- bodyPage := es.newEmailTemplate("payment_failed_body", locale)
- bodyPage.Props["SiteURL"] = siteURL
- bodyPage.Props["Title"] = T("api.templates.payment_failed.title")
- bodyPage.Props["Info1"] = T("api.templates.payment_failed.info1", map[string]interface{}{"CardBrand": failedPayment.CardBrand, "LastFour": failedPayment.LastFour})
- bodyPage.Props["Info2"] = T("api.templates.payment_failed.info2")
- bodyPage.Props["Info3"] = T("api.templates.payment_failed.info3")
- bodyPage.Props["Button"] = T("api.templates.over_limit_fix_now")
- bodyPage.Props["EmailUs"] = T("api.templates.email_us_anytime_at")
+ data := es.newEmailTemplateData(locale)
+ data.Props["SiteURL"] = siteURL
+ data.Props["Title"] = T("api.templates.payment_failed.title")
+ data.Props["Info1"] = T("api.templates.payment_failed.info1", map[string]interface{}{"CardBrand": failedPayment.CardBrand, "LastFour": failedPayment.LastFour})
+ data.Props["Info2"] = T("api.templates.payment_failed.info2")
+ data.Props["Info3"] = T("api.templates.payment_failed.info3")
+ data.Props["Button"] = T("api.templates.over_limit_fix_now")
+ data.Props["EmailUs"] = T("api.templates.email_us_anytime_at")
- bodyPage.Props["Footer"] = T("api.templates.copyright")
+ data.Props["Footer"] = T("api.templates.copyright")
- bodyPage.Props["FailedReason"] = failedPayment.FailureMessage
+ data.Props["FailedReason"] = failedPayment.FailureMessage
- if err := es.sendMail(email, subject, bodyPage.Render()); err != nil {
+ body, err := es.srv.TemplatesContainer().RenderToString("payment_failed_body", data)
+ if err != nil {
+ return false, model.NewAppError("SendPaymentFailedEmail", "api.user.send_password_reset.send.app_error", nil, "err="+err.Error(), http.StatusInternalServerError)
+ }
+
+ if err := es.sendMail(email, subject, body); err != nil {
return false, model.NewAppError("SendPaymentFailedEmail", "api.user.send_password_reset.send.app_error", nil, "err="+err.Error(), http.StatusInternalServerError)
}
@@ -897,17 +1023,22 @@ func (es *EmailService) SendNoCardPaymentFailedEmail(email string, locale string
subject := T("api.templates.payment_failed_no_card.subject")
- bodyPage := es.newEmailTemplate("payment_failed_no_card_body", locale)
- bodyPage.Props["SiteURL"] = siteURL
- bodyPage.Props["Title"] = T("api.templates.payment_failed_no_card.title")
- bodyPage.Props["Info1"] = T("api.templates.payment_failed_no_card.info1")
- bodyPage.Props["Info3"] = T("api.templates.payment_failed_no_card.info3")
- bodyPage.Props["Button"] = T("api.templates.payment_failed_no_card.button")
- bodyPage.Props["EmailUs"] = T("api.templates.email_us_anytime_at")
+ data := es.newEmailTemplateData(locale)
+ data.Props["SiteURL"] = siteURL
+ data.Props["Title"] = T("api.templates.payment_failed_no_card.title")
+ data.Props["Info1"] = T("api.templates.payment_failed_no_card.info1")
+ data.Props["Info3"] = T("api.templates.payment_failed_no_card.info3")
+ data.Props["Button"] = T("api.templates.payment_failed_no_card.button")
+ data.Props["EmailUs"] = T("api.templates.email_us_anytime_at")
- bodyPage.Props["Footer"] = T("api.templates.copyright")
+ data.Props["Footer"] = T("api.templates.copyright")
- if err := es.sendMail(email, subject, bodyPage.Render()); err != nil {
+ body, err := es.srv.TemplatesContainer().RenderToString("payment_failed_no_card_body", data)
+ if err != nil {
+ return model.NewAppError("SendPaymentFailedEmail", "api.user.send_password_reset.send.app_error", nil, "err="+err.Error(), http.StatusInternalServerError)
+ }
+
+ if err := es.sendMail(email, subject, body); err != nil {
return model.NewAppError("SendPaymentFailedEmail", "api.user.send_password_reset.send.app_error", nil, "err="+err.Error(), http.StatusInternalServerError)
}
diff --git a/app/email_batching.go b/app/email_batching.go
index 31f2054d90..514805c76e 100644
--- a/app/email_batching.go
+++ b/app/email_batching.go
@@ -15,7 +15,6 @@ import (
"github.com/mattermost/mattermost-server/v5/model"
"github.com/mattermost/mattermost-server/v5/shared/i18n"
"github.com/mattermost/mattermost-server/v5/shared/mlog"
- "github.com/mattermost/mattermost-server/v5/utils"
)
const (
@@ -222,7 +221,13 @@ func (es *EmailService) sendBatchedEmailNotification(userID string, notification
emailNotificationContentsType = *es.srv.Config().EmailSettings.EmailNotificationContentsType
}
- contents += es.renderBatchedPost(notification, channel, sender, *es.srv.Config().ServiceSettings.SiteURL, displayNameFormat, translateFunc, user.Locale, emailNotificationContentsType)
+ postContent, err := es.renderBatchedPost(notification, channel, sender, *es.srv.Config().ServiceSettings.SiteURL, displayNameFormat, translateFunc, user.Locale, emailNotificationContentsType)
+ if err != nil {
+ mlog.Warn("Unable to render post for batched email notification template", mlog.Err(err))
+ continue
+ }
+
+ contents += postContent
}
tm := time.Unix(notifications[0].post.CreateAt/1000, 0)
@@ -234,34 +239,39 @@ func (es *EmailService) sendBatchedEmailNotification(userID string, notification
"Day": tm.Day(),
})
- body := es.newEmailTemplate("post_batched_body", user.Locale)
- body.Props["SiteURL"] = *es.srv.Config().ServiceSettings.SiteURL
- body.Props["Posts"] = template.HTML(contents)
- body.Props["BodyText"] = translateFunc("api.email_batching.send_batched_email_notification.body_text", len(notifications))
+ data := es.newEmailTemplateData(user.Locale)
+ data.Props["SiteURL"] = *es.srv.Config().ServiceSettings.SiteURL
+ data.Props["Posts"] = template.HTML(contents)
+ data.Props["BodyText"] = translateFunc("api.email_batching.send_batched_email_notification.body_text", len(notifications))
- if nErr := es.sendNotificationMail(user.Email, subject, body.Render()); nErr != nil {
+ body, err2 := es.srv.TemplatesContainer().RenderToString("post_batched_body", data)
+ if err2 != nil {
+ mlog.Warn("Unable build the batched email notification template", mlog.Err(err2))
+ return
+ }
+
+ if nErr := es.sendNotificationMail(user.Email, subject, body); nErr != nil {
mlog.Warn("Unable to send batched email notification", mlog.String("email", user.Email), mlog.Err(nErr))
}
}
-func (es *EmailService) renderBatchedPost(notification *batchedNotification, channel *model.Channel, sender *model.User, siteURL string, displayNameFormat string, translateFunc i18n.TranslateFunc, userLocale string, emailNotificationContentsType string) string {
+func (es *EmailService) renderBatchedPost(notification *batchedNotification, channel *model.Channel, sender *model.User, siteURL string, displayNameFormat string, translateFunc i18n.TranslateFunc, userLocale string, emailNotificationContentsType string) (string, error) {
// don't include message contents if email notification contents type is set to generic
- var template *utils.HTMLTemplate
+ var templateName = "post_batched_post_generic"
if emailNotificationContentsType == model.EMAIL_NOTIFICATION_CONTENTS_FULL {
- template = es.newEmailTemplate("post_batched_post_full", userLocale)
- } else {
- template = es.newEmailTemplate("post_batched_post_generic", userLocale)
+ templateName = "post_batched_post_full"
}
- template.Props["Button"] = translateFunc("api.email_batching.render_batched_post.go_to_post")
- template.Props["PostMessage"] = es.srv.GetMessageForNotification(notification.post, translateFunc)
- template.Props["PostLink"] = siteURL + "/" + notification.teamName + "/pl/" + notification.post.Id
- template.Props["SenderName"] = sender.GetDisplayName(displayNameFormat)
+ data := es.newEmailTemplateData(userLocale)
+ data.Props["Button"] = translateFunc("api.email_batching.render_batched_post.go_to_post")
+ data.Props["PostMessage"] = es.srv.GetMessageForNotification(notification.post, translateFunc)
+ data.Props["PostLink"] = siteURL + "/" + notification.teamName + "/pl/" + notification.post.Id
+ data.Props["SenderName"] = sender.GetDisplayName(displayNameFormat)
tm := time.Unix(notification.post.CreateAt/1000, 0)
timezone, _ := tm.Zone()
- template.Props["Date"] = translateFunc("api.email_batching.render_batched_post.date", map[string]interface{}{
+ data.Props["Date"] = translateFunc("api.email_batching.render_batched_post.date", map[string]interface{}{
"Year": tm.Year(),
"Month": translateFunc(tm.Month().String()),
"Day": tm.Day(),
@@ -271,17 +281,17 @@ func (es *EmailService) renderBatchedPost(notification *batchedNotification, cha
})
if channel.Type == model.CHANNEL_DIRECT {
- template.Props["ChannelName"] = translateFunc("api.email_batching.render_batched_post.direct_message")
+ data.Props["ChannelName"] = translateFunc("api.email_batching.render_batched_post.direct_message")
} else if channel.Type == model.CHANNEL_GROUP {
- template.Props["ChannelName"] = translateFunc("api.email_batching.render_batched_post.group_message")
+ data.Props["ChannelName"] = translateFunc("api.email_batching.render_batched_post.group_message")
} else {
// don't include channel name if email notification contents type is set to generic
if emailNotificationContentsType == model.EMAIL_NOTIFICATION_CONTENTS_FULL {
- template.Props["ChannelName"] = channel.DisplayName
+ data.Props["ChannelName"] = channel.DisplayName
} else {
- template.Props["ChannelName"] = translateFunc("api.email_batching.render_batched_post.notification")
+ data.Props["ChannelName"] = translateFunc("api.email_batching.render_batched_post.notification")
}
}
- return template.Render()
+ return es.srv.TemplatesContainer().RenderToString(templateName, data)
}
diff --git a/app/email_batching_test.go b/app/email_batching_test.go
index 561af30333..6543200309 100644
--- a/app/email_batching_test.go
+++ b/app/email_batching_test.go
@@ -304,7 +304,8 @@ func TestRenderBatchedPostGeneric(t *testing.T) {
return translationID
}
- var rendered = th.Server.EmailService.renderBatchedPost(notification, channel, sender, "http://localhost:8065", "", translateFunc, "en", model.EMAIL_NOTIFICATION_CONTENTS_GENERIC)
+ rendered, err := th.Server.EmailService.renderBatchedPost(notification, channel, sender, "http://localhost:8065", "", translateFunc, "en", model.EMAIL_NOTIFICATION_CONTENTS_GENERIC)
+ require.NoError(t, err)
require.NotContains(t, rendered, post.Message, "Rendered email should not contain post contents when email notification contents type is set to Generic.")
}
@@ -329,6 +330,7 @@ func TestRenderBatchedPostFull(t *testing.T) {
return translationID
}
- var rendered = th.Server.EmailService.renderBatchedPost(notification, channel, sender, "http://localhost:8065", "", translateFunc, "en", model.EMAIL_NOTIFICATION_CONTENTS_FULL)
+ rendered, err := th.Server.EmailService.renderBatchedPost(notification, channel, sender, "http://localhost:8065", "", translateFunc, "en", model.EMAIL_NOTIFICATION_CONTENTS_FULL)
+ require.NoError(t, err)
require.Contains(t, rendered, post.Message, "Rendered email should contain post contents when email notification contents type is set to Full.")
}
diff --git a/app/notification.go b/app/notification.go
index db311ef923..cdf55a18da 100644
--- a/app/notification.go
+++ b/app/notification.go
@@ -231,7 +231,10 @@ func (a *App) SendNotifications(post *model.Post, team *model.Team, channel *mod
}
if a.userAllowsEmail(profileMap[id], channelMemberNotifyPropsMap[id], post) {
- a.sendNotificationEmail(notification, profileMap[id], team)
+ err := a.sendNotificationEmail(notification, profileMap[id], team)
+ if err != nil {
+ mlog.Warn("Unable to send notification email.", mlog.Err(err))
+ }
}
}
}
diff --git a/app/notification_email.go b/app/notification_email.go
index 81fc15e350..ef9f065e6f 100644
--- a/app/notification_email.go
+++ b/app/notification_email.go
@@ -7,7 +7,6 @@ import (
"fmt"
"html"
"html/template"
- "net/http"
"net/url"
"path/filepath"
"strings"
@@ -16,17 +15,17 @@ import (
"github.com/mattermost/mattermost-server/v5/model"
"github.com/mattermost/mattermost-server/v5/shared/i18n"
"github.com/mattermost/mattermost-server/v5/shared/mlog"
- "github.com/mattermost/mattermost-server/v5/utils"
+ "github.com/pkg/errors"
)
-func (a *App) sendNotificationEmail(notification *PostNotification, user *model.User, team *model.Team) *model.AppError {
+func (a *App) sendNotificationEmail(notification *PostNotification, user *model.User, team *model.Team) error {
channel := notification.Channel
post := notification.Post
if channel.IsGroupOrDirect() {
teams, err := a.Srv().Store.Team().GetTeamsByUserId(user.Id)
if err != nil {
- return model.NewAppError("sendNotificationEmail", "app.team.get_all.app_error", nil, err.Error(), http.StatusInternalServerError)
+ return errors.Wrap(err, "unable to get user teams")
}
// if the recipient isn't in the current user's team, just pick one
@@ -97,7 +96,10 @@ func (a *App) sendNotificationEmail(notification *PostNotification, user *model.
}
landingURL := a.GetSiteURL() + "/landing#/" + team.Name
- var bodyText = a.getNotificationEmailBody(user, post, channel, channelName, senderName, team.Name, landingURL, emailNotificationContentsType, useMilitaryTime, translateFunc)
+ var bodyText, err = a.getNotificationEmailBody(user, post, channel, channelName, senderName, team.Name, landingURL, emailNotificationContentsType, useMilitaryTime, translateFunc)
+ if err != nil {
+ return errors.Wrap(err, "unable to render the email notification template")
+ }
a.Srv().Go(func() {
if nErr := a.Srv().EmailService.sendNotificationMail(user.Email, html.UnescapeString(subjectText), bodyText); nErr != nil {
@@ -163,11 +165,12 @@ func getGroupMessageNotificationEmailSubject(user *model.User, post *model.Post,
/**
* Computes the email body for notification messages
*/
-func (a *App) getNotificationEmailBody(recipient *model.User, post *model.Post, channel *model.Channel, channelName string, senderName string, teamName string, landingURL string, emailNotificationContentsType string, useMilitaryTime bool, translateFunc i18n.TranslateFunc) string {
+func (a *App) getNotificationEmailBody(recipient *model.User, post *model.Post, channel *model.Channel, channelName string, senderName string, teamName string, landingURL string, emailNotificationContentsType string, useMilitaryTime bool, translateFunc i18n.TranslateFunc) (string, error) {
// only include message contents in notification email if email notification contents type is set to full
- var bodyPage *utils.HTMLTemplate
+ var templateName = "post_body_generic"
+ data := a.Srv().EmailService.newEmailTemplateData(recipient.Locale)
if emailNotificationContentsType == model.EMAIL_NOTIFICATION_CONTENTS_FULL {
- bodyPage = a.Srv().EmailService.newEmailTemplate("post_body_full", recipient.Locale)
+ templateName = "post_body_full"
postMessage := a.GetMessageForNotification(post, translateFunc)
postMessage = html.EscapeString(postMessage)
normalizedPostMessage, err := a.generateHyperlinkForChannels(postMessage, teamName, landingURL)
@@ -175,16 +178,14 @@ func (a *App) getNotificationEmailBody(recipient *model.User, post *model.Post,
mlog.Warn("Encountered error while generating hyperlink for channels", mlog.String("team_name", teamName), mlog.Err(err))
normalizedPostMessage = postMessage
}
- bodyPage.Props["PostMessage"] = template.HTML(normalizedPostMessage)
- } else {
- bodyPage = a.Srv().EmailService.newEmailTemplate("post_body_generic", recipient.Locale)
+ data.Props["PostMessage"] = template.HTML(normalizedPostMessage)
}
- bodyPage.Props["SiteURL"] = a.GetSiteURL()
+ data.Props["SiteURL"] = a.GetSiteURL()
if teamName != "select_team" {
- bodyPage.Props["TeamLink"] = landingURL + "/pl/" + post.Id
+ data.Props["TeamLink"] = landingURL + "/pl/" + post.Id
} else {
- bodyPage.Props["TeamLink"] = landingURL
+ data.Props["TeamLink"] = landingURL
}
t := getFormattedPostTime(recipient, post, useMilitaryTime, translateFunc)
@@ -198,51 +199,51 @@ func (a *App) getNotificationEmailBody(recipient *model.User, post *model.Post,
}
if channel.Type == model.CHANNEL_DIRECT {
if emailNotificationContentsType == model.EMAIL_NOTIFICATION_CONTENTS_FULL {
- bodyPage.Props["BodyText"] = translateFunc("app.notification.body.intro.direct.full")
- bodyPage.Props["Info1"] = ""
+ data.Props["BodyText"] = translateFunc("app.notification.body.intro.direct.full")
+ data.Props["Info1"] = ""
info["SenderName"] = senderName
- bodyPage.Props["Info2"] = translateFunc("app.notification.body.text.direct.full", info)
+ data.Props["Info2"] = translateFunc("app.notification.body.text.direct.full", info)
} else {
- bodyPage.Props["BodyText"] = translateFunc("app.notification.body.intro.direct.generic", map[string]interface{}{
+ data.Props["BodyText"] = translateFunc("app.notification.body.intro.direct.generic", map[string]interface{}{
"SenderName": senderName,
})
- bodyPage.Props["Info"] = translateFunc("app.notification.body.text.direct.generic", info)
+ data.Props["Info"] = translateFunc("app.notification.body.text.direct.generic", info)
}
} else if channel.Type == model.CHANNEL_GROUP {
if emailNotificationContentsType == model.EMAIL_NOTIFICATION_CONTENTS_FULL {
- bodyPage.Props["BodyText"] = translateFunc("app.notification.body.intro.group_message.full")
- bodyPage.Props["Info1"] = translateFunc("app.notification.body.text.group_message.full",
+ data.Props["BodyText"] = translateFunc("app.notification.body.intro.group_message.full")
+ data.Props["Info1"] = translateFunc("app.notification.body.text.group_message.full",
map[string]interface{}{
"ChannelName": channelName,
})
info["SenderName"] = senderName
- bodyPage.Props["Info2"] = translateFunc("app.notification.body.text.group_message.full2", info)
+ data.Props["Info2"] = translateFunc("app.notification.body.text.group_message.full2", info)
} else {
- bodyPage.Props["BodyText"] = translateFunc("app.notification.body.intro.group_message.generic", map[string]interface{}{
+ data.Props["BodyText"] = translateFunc("app.notification.body.intro.group_message.generic", map[string]interface{}{
"SenderName": senderName,
})
- bodyPage.Props["Info"] = translateFunc("app.notification.body.text.group_message.generic", info)
+ data.Props["Info"] = translateFunc("app.notification.body.text.group_message.generic", info)
}
} else {
if emailNotificationContentsType == model.EMAIL_NOTIFICATION_CONTENTS_FULL {
- bodyPage.Props["BodyText"] = translateFunc("app.notification.body.intro.notification.full")
- bodyPage.Props["Info1"] = translateFunc("app.notification.body.text.notification.full",
+ data.Props["BodyText"] = translateFunc("app.notification.body.intro.notification.full")
+ data.Props["Info1"] = translateFunc("app.notification.body.text.notification.full",
map[string]interface{}{
"ChannelName": channelName,
})
info["SenderName"] = senderName
- bodyPage.Props["Info2"] = translateFunc("app.notification.body.text.notification.full2", info)
+ data.Props["Info2"] = translateFunc("app.notification.body.text.notification.full2", info)
} else {
- bodyPage.Props["BodyText"] = translateFunc("app.notification.body.intro.notification.generic", map[string]interface{}{
+ data.Props["BodyText"] = translateFunc("app.notification.body.intro.notification.generic", map[string]interface{}{
"SenderName": senderName,
})
- bodyPage.Props["Info"] = translateFunc("app.notification.body.text.notification.generic", info)
+ data.Props["Info"] = translateFunc("app.notification.body.text.notification.generic", info)
}
}
- bodyPage.Props["Button"] = translateFunc("api.templates.post_body.button")
+ data.Props["Button"] = translateFunc("api.templates.post_body.button")
- return bodyPage.Render()
+ return a.Srv().TemplatesContainer().RenderToString(templateName, data)
}
type formattedPostTime struct {
diff --git a/app/notification_email_test.go b/app/notification_email_test.go
index cee9500e8e..bc24389899 100644
--- a/app/notification_email_test.go
+++ b/app/notification_email_test.go
@@ -91,7 +91,8 @@ func TestGetNotificationEmailBodyFullNotificationPublicChannel(t *testing.T) {
teamStoreMock.On("GetByName", "testteam").Return(&model.Team{Name: "testteam"}, nil)
storeMock.On("Team").Return(&teamStoreMock)
- body := th.App.getNotificationEmailBody(recipient, post, channel, channelName, senderName, teamName, teamURL, emailNotificationContentsType, true, translateFunc)
+ body, err := th.App.getNotificationEmailBody(recipient, post, channel, channelName, senderName, teamName, teamURL, emailNotificationContentsType, true, translateFunc)
+ require.NoError(t, err)
require.Contains(t, body, "You have a new notification.", fmt.Sprintf("Expected email text 'You have a new notification. Got %s", body))
require.Contains(t, body, "Channel: "+channel.DisplayName, "Expected email text 'Channel: %s'. Got %s", channel.DisplayName, body)
require.Contains(t, body, senderName+" - ", fmt.Sprintf("Expected email text '%s - '. Got %s", senderName, body))
@@ -123,7 +124,8 @@ func TestGetNotificationEmailBodyFullNotificationGroupChannel(t *testing.T) {
teamStoreMock.On("GetByName", "testteam").Return(&model.Team{Name: "testteam"}, nil)
storeMock.On("Team").Return(&teamStoreMock)
- body := th.App.getNotificationEmailBody(recipient, post, channel, channelName, senderName, teamName, teamURL, emailNotificationContentsType, true, translateFunc)
+ body, err := th.App.getNotificationEmailBody(recipient, post, channel, channelName, senderName, teamName, teamURL, emailNotificationContentsType, true, translateFunc)
+ require.NoError(t, err)
require.Contains(t, body, "You have a new Group Message.", fmt.Sprintf("Expected email text 'You have a new Group Message. Got "+body))
require.Contains(t, body, "Channel: ChannelName", fmt.Sprintf("Expected email text 'Channel: ChannelName'. Got %s", body))
require.Contains(t, body, senderName+" - ", fmt.Sprintf("Expected email text '%s - '. Got %s", senderName, body))
@@ -155,7 +157,8 @@ func TestGetNotificationEmailBodyFullNotificationPrivateChannel(t *testing.T) {
teamStoreMock.On("GetByName", "testteam").Return(&model.Team{Name: "testteam"}, nil)
storeMock.On("Team").Return(&teamStoreMock)
- body := th.App.getNotificationEmailBody(recipient, post, channel, channelName, senderName, teamName, teamURL, emailNotificationContentsType, true, translateFunc)
+ body, err := th.App.getNotificationEmailBody(recipient, post, channel, channelName, senderName, teamName, teamURL, emailNotificationContentsType, true, translateFunc)
+ require.NoError(t, err)
require.Contains(t, body, "You have a new notification.", fmt.Sprintf("Expected email text 'You have a new notification. Got "+body))
require.Contains(t, body, "Channel: "+channel.DisplayName, fmt.Sprintf("Expected email text 'Channel: "+channel.DisplayName+"'. Got "+body))
require.Contains(t, body, senderName+" - ", fmt.Sprintf("Expected email text '%s - '. Got %s", senderName, body))
@@ -187,7 +190,8 @@ func TestGetNotificationEmailBodyFullNotificationDirectChannel(t *testing.T) {
teamStoreMock.On("GetByName", "testteam").Return(&model.Team{Name: "testteam"}, nil)
storeMock.On("Team").Return(&teamStoreMock)
- body := th.App.getNotificationEmailBody(recipient, post, channel, channelName, senderName, teamName, teamURL, emailNotificationContentsType, true, translateFunc)
+ body, err := th.App.getNotificationEmailBody(recipient, post, channel, channelName, senderName, teamName, teamURL, emailNotificationContentsType, true, translateFunc)
+ require.NoError(t, err)
require.Contains(t, body, "You have a new Direct Message.", fmt.Sprintf("Expected email text 'You have a new Direct Message. Got "+body))
require.Contains(t, body, senderName+" - ", fmt.Sprintf("Expected email text '%s - '. Got %s", senderName, body))
require.Contains(t, body, post.Message, fmt.Sprintf("Expected email text '%s'. Got %s", post.Message, body))
@@ -222,7 +226,8 @@ func TestGetNotificationEmailBodyFullNotificationLocaleTimeWithTimezone(t *testi
teamStoreMock.On("GetByName", "testteam").Return(&model.Team{Name: "testteam"}, nil)
storeMock.On("Team").Return(&teamStoreMock)
- body := th.App.getNotificationEmailBody(recipient, post, channel, channelName, senderName, teamName, teamURL, emailNotificationContentsType, false, translateFunc)
+ body, err := th.App.getNotificationEmailBody(recipient, post, channel, channelName, senderName, teamName, teamURL, emailNotificationContentsType, false, translateFunc)
+ require.NoError(t, err)
r, _ := regexp.Compile("E([S|D]+)T")
zone := r.FindString(body)
require.Contains(t, body, "sender - 9:43 AM "+zone+", April 25", fmt.Sprintf("Expected email text 'sender - 9:43 AM %s, April 25'. Got %s", zone, body))
@@ -274,7 +279,8 @@ func TestGetNotificationEmailBodyFullNotificationLocaleTimeNoTimezone(t *testing
err = tmp.Execute(&text, fmt.Sprintf("sender - %s:%s %s, %s %s", formattedTime.Hour, formattedTime.Minute, formattedTime.TimeZone, formattedTime.Month, formattedTime.Day))
require.NoError(t, err)
- body := th.App.getNotificationEmailBody(recipient, post, channel, channelName, senderName, teamName, teamURL, emailNotificationContentsType, true, translateFunc)
+ body, err := th.App.getNotificationEmailBody(recipient, post, channel, channelName, senderName, teamName, teamURL, emailNotificationContentsType, true, translateFunc)
+ require.NoError(t, err)
postTimeLine := text.String()
require.Contains(t, body, postTimeLine, fmt.Sprintf("Expected email text '%s'. Got %s", postTimeLine, body))
}
@@ -307,7 +313,8 @@ func TestGetNotificationEmailBodyFullNotificationLocaleTime12Hour(t *testing.T)
teamStoreMock.On("GetByName", "testteam").Return(&model.Team{Name: "testteam"}, nil)
storeMock.On("Team").Return(&teamStoreMock)
- body := th.App.getNotificationEmailBody(recipient, post, channel, channelName, senderName, teamName, teamURL, emailNotificationContentsType, false, translateFunc)
+ body, err := th.App.getNotificationEmailBody(recipient, post, channel, channelName, senderName, teamName, teamURL, emailNotificationContentsType, false, translateFunc)
+ require.NoError(t, err)
require.Contains(t, body, "sender - 2:30 PM", fmt.Sprintf("Expected email text 'sender - 2:30 PM'. Got %s", body))
require.Contains(t, body, "April 25", fmt.Sprintf("Expected email text 'April 25'. Got %s", body))
}
@@ -340,7 +347,8 @@ func TestGetNotificationEmailBodyFullNotificationLocaleTime24Hour(t *testing.T)
teamStoreMock.On("GetByName", "testteam").Return(&model.Team{Name: "testteam"}, nil)
storeMock.On("Team").Return(&teamStoreMock)
- body := th.App.getNotificationEmailBody(recipient, post, channel, channelName, senderName, teamName, teamURL, emailNotificationContentsType, true, translateFunc)
+ body, err := th.App.getNotificationEmailBody(recipient, post, channel, channelName, senderName, teamName, teamURL, emailNotificationContentsType, true, translateFunc)
+ require.NoError(t, err)
require.Contains(t, body, "sender - 14:30", fmt.Sprintf("Expected email text 'sender - 14:30'. Got %s", body))
require.Contains(t, body, "April 25", fmt.Sprintf("Expected email text 'April 25'. Got %s", body))
}
@@ -370,7 +378,8 @@ func TestGetNotificationEmailBodyGenericNotificationPublicChannel(t *testing.T)
teamStoreMock.On("GetByName", "testteam").Return(&model.Team{Name: "testteam"}, nil)
storeMock.On("Team").Return(&teamStoreMock)
- body := th.App.getNotificationEmailBody(recipient, post, channel, channelName, senderName, teamName, teamURL, emailNotificationContentsType, true, translateFunc)
+ body, err := th.App.getNotificationEmailBody(recipient, post, channel, channelName, senderName, teamName, teamURL, emailNotificationContentsType, true, translateFunc)
+ require.NoError(t, err)
require.Contains(t, body, "You have a new notification from "+senderName, fmt.Sprintf("Expected email text 'You have a new notification from %s'. Got %s", senderName, body))
require.False(t, strings.Contains(body, "Channel: "+channel.DisplayName), fmt.Sprintf("Did not expect email text 'CHANNEL: %s'. Got %s", channel.DisplayName, body))
require.False(t, strings.Contains(body, post.Message), fmt.Sprintf("Did not expect email text '%s'. Got %s", post.Message, body))
@@ -401,7 +410,8 @@ func TestGetNotificationEmailBodyGenericNotificationGroupChannel(t *testing.T) {
teamStoreMock.On("GetByName", "testteam").Return(&model.Team{Name: "testteam"}, nil)
storeMock.On("Team").Return(&teamStoreMock)
- body := th.App.getNotificationEmailBody(recipient, post, channel, channelName, senderName, teamName, teamURL, emailNotificationContentsType, true, translateFunc)
+ body, err := th.App.getNotificationEmailBody(recipient, post, channel, channelName, senderName, teamName, teamURL, emailNotificationContentsType, true, translateFunc)
+ require.NoError(t, err)
require.Contains(t, body, "You have a new Group Message from "+senderName, fmt.Sprintf("Expected email text 'You have a new Group Message from %s'. Got %s", senderName, body))
require.False(t, strings.Contains(body, "CHANNEL: "+channel.DisplayName), fmt.Sprintf("Did not expect email text 'CHANNEL: %s'. Got %s", channel.DisplayName, body))
require.False(t, strings.Contains(body, post.Message), fmt.Sprintf("Did not expect email text '%s'. Got %s", post.Message, body))
@@ -432,7 +442,8 @@ func TestGetNotificationEmailBodyGenericNotificationPrivateChannel(t *testing.T)
teamStoreMock.On("GetByName", "testteam").Return(&model.Team{Name: "testteam"}, nil)
storeMock.On("Team").Return(&teamStoreMock)
- body := th.App.getNotificationEmailBody(recipient, post, channel, channelName, senderName, teamName, teamURL, emailNotificationContentsType, true, translateFunc)
+ body, err := th.App.getNotificationEmailBody(recipient, post, channel, channelName, senderName, teamName, teamURL, emailNotificationContentsType, true, translateFunc)
+ require.NoError(t, err)
require.Contains(t, body, "You have a new notification from "+senderName, fmt.Sprintf("Expected email text 'You have a new notification from %s'. Got %s", senderName, body))
require.False(t, strings.Contains(body, "CHANNEL: "+channel.DisplayName), fmt.Sprintf("Did not expect email text 'CHANNEL: %s'. Got %s", channel.DisplayName, body))
require.False(t, strings.Contains(body, post.Message), fmt.Sprintf("Did not expect email text '%s'. Got %s", post.Message, body))
@@ -463,7 +474,8 @@ func TestGetNotificationEmailBodyGenericNotificationDirectChannel(t *testing.T)
teamStoreMock.On("GetByName", "testteam").Return(&model.Team{Name: "testteam"}, nil)
storeMock.On("Team").Return(&teamStoreMock)
- body := th.App.getNotificationEmailBody(recipient, post, channel, channelName, senderName, teamName, teamURL, emailNotificationContentsType, true, translateFunc)
+ body, err := th.App.getNotificationEmailBody(recipient, post, channel, channelName, senderName, teamName, teamURL, emailNotificationContentsType, true, translateFunc)
+ require.NoError(t, err)
require.Contains(t, body, "You have a new Direct Message from "+senderName, fmt.Sprintf("Expected email text 'You have a new Direct Message from "+senderName+"'. Got "+body))
require.False(t, strings.Contains(body, "CHANNEL: "+channel.DisplayName), fmt.Sprintf("Did not expect email text 'CHANNEL: %s'. Got %s", channel.DisplayName, body))
require.False(t, strings.Contains(body, post.Message), fmt.Sprintf("Did not expect email text '%s'. Got %s", post.Message, body))
@@ -496,9 +508,10 @@ func TestGetNotificationEmailEscapingChars(t *testing.T) {
teamStoreMock.On("GetByName", "testteam").Return(&model.Team{Name: "testteam"}, nil)
storeMock.On("Team").Return(&teamStoreMock)
- body := th.App.getNotificationEmailBody(recipient, post, ch,
+ body, err := th.App.getNotificationEmailBody(recipient, post, ch,
channelName, senderName, teamName, teamURL,
emailNotificationContentsType, true, translateFunc)
+ require.NoError(t, err)
assert.NotContains(t, body, message)
}
@@ -539,9 +552,10 @@ func TestGetNotificationEmailBodyPublicChannelMention(t *testing.T) {
channelStoreMock.On("GetByNames", "test", []string{ch.Name}, true).Return([]*model.Channel{ch}, nil)
storeMock.On("Channel").Return(&channelStoreMock)
- body := th.App.getNotificationEmailBody(recipient, post, ch,
+ body, err := th.App.getNotificationEmailBody(recipient, post, ch,
ch.Name, senderName, teamName, teamURL,
emailNotificationContentsType, true, translateFunc)
+ require.NoError(t, err)
channelURL := teamURL + "/channels/" + ch.Name
mention := "~" + ch.Name
assert.Contains(t, body, ""+mention+"")
@@ -604,9 +618,10 @@ func TestGetNotificationEmailBodyMultiPublicChannelMention(t *testing.T) {
channelStoreMock.On("GetByNames", "test", []string{ch.Name, ch2.Name, ch3.Name}, true).Return([]*model.Channel{ch, ch2, ch3}, nil)
storeMock.On("Channel").Return(&channelStoreMock)
- body := th.App.getNotificationEmailBody(recipient, post, ch,
+ body, err := th.App.getNotificationEmailBody(recipient, post, ch,
ch.Name, senderName, teamName, teamURL,
emailNotificationContentsType, true, translateFunc)
+ require.NoError(t, err)
channelURL := teamURL + "/channels/" + ch.Name
channelURL2 := teamURL + "/channels/" + ch2.Name
channelURL3 := teamURL + "/channels/" + ch3.Name
@@ -652,9 +667,10 @@ func TestGetNotificationEmailBodyPrivateChannelMention(t *testing.T) {
channelStoreMock.On("GetByNames", "test", []string{ch.Name}, true).Return([]*model.Channel{ch}, nil)
storeMock.On("Channel").Return(&channelStoreMock)
- body := th.App.getNotificationEmailBody(recipient, post, ch,
+ body, err := th.App.getNotificationEmailBody(recipient, post, ch,
ch.Name, senderName, teamName, teamURL,
emailNotificationContentsType, true, translateFunc)
+ require.NoError(t, err)
channelURL := teamURL + "/channels/" + ch.Name
mention := "~" + ch.Name
assert.NotContains(t, body, ""+mention+"")
@@ -797,7 +813,8 @@ func TestLandingLink(t *testing.T) {
teamStoreMock.On("GetByName", "testteam").Return(&model.Team{Name: "testteam"}, nil)
storeMock.On("Team").Return(&teamStoreMock)
- body := th.App.getNotificationEmailBody(recipient, post, channel, channelName, senderName, teamName, teamURL, emailNotificationContentsType, true, translateFunc)
+ body, err := th.App.getNotificationEmailBody(recipient, post, channel, channelName, senderName, teamName, teamURL, emailNotificationContentsType, true, translateFunc)
+ require.NoError(t, err)
require.Contains(t, body, teamURL, fmt.Sprintf("Expected email text '%s'. Got %s", teamURL, body))
}
@@ -826,6 +843,7 @@ func TestLandingLinkPermalink(t *testing.T) {
teamStoreMock.On("GetByName", "testteam").Return(&model.Team{Name: "testteam"}, nil)
storeMock.On("Team").Return(&teamStoreMock)
- body := th.App.getNotificationEmailBody(recipient, post, channel, channelName, senderName, teamName, teamURL, emailNotificationContentsType, true, translateFunc)
+ body, err := th.App.getNotificationEmailBody(recipient, post, channel, channelName, senderName, teamName, teamURL, emailNotificationContentsType, true, translateFunc)
+ require.NoError(t, err)
require.Contains(t, body, teamURL+"/pl/"+post.Id, fmt.Sprintf("Expected email text '%s'. Got %s", teamURL, body))
}
diff --git a/app/server.go b/app/server.go
index f2520de07b..36f94e0694 100644
--- a/app/server.go
+++ b/app/server.go
@@ -58,6 +58,7 @@ import (
"github.com/mattermost/mattermost-server/v5/shared/filestore"
"github.com/mattermost/mattermost-server/v5/shared/i18n"
"github.com/mattermost/mattermost-server/v5/shared/mlog"
+ "github.com/mattermost/mattermost-server/v5/shared/templates"
"github.com/mattermost/mattermost-server/v5/store"
"github.com/mattermost/mattermost-server/v5/store/localcachelayer"
"github.com/mattermost/mattermost-server/v5/store/retrylayer"
@@ -65,6 +66,7 @@ import (
"github.com/mattermost/mattermost-server/v5/store/sqlstore"
"github.com/mattermost/mattermost-server/v5/store/timerlayer"
"github.com/mattermost/mattermost-server/v5/utils"
+ "github.com/mattermost/mattermost-server/v5/utils/fileutils"
)
var MaxNotificationsPerChannelDefault int64 = 1000000
@@ -133,7 +135,7 @@ type Server struct {
newStore func() (store.Store, error)
- htmlTemplateWatcher *utils.HTMLTemplateWatcher
+ htmlTemplateWatcher *templates.Container
sessionCache cache.Cache
seenPendingPostIdsCache cache.Cache
statusCache cache.Cache
@@ -391,9 +393,19 @@ func NewServer(options ...Option) (*Server, error) {
}
}
- if htmlTemplateWatcher, err2 := utils.NewHTMLTemplateWatcher("templates"); err2 != nil {
- mlog.Error("Failed to parse server templates", mlog.Err(err2))
+ templatesDir, ok := fileutils.FindDir("templates")
+ if !ok {
+ mlog.Error("Failed find server templates", mlog.String("directory", "templates"))
} else {
+ htmlTemplateWatcher, errorsChan, err2 := templates.NewWithWatcher(templatesDir)
+ if err2 != nil {
+ return nil, errors.Wrap(err2, "cannot initialize server templates")
+ }
+ s.Go(func() {
+ for err2 := range errorsChan {
+ mlog.Warn("Server templates error", mlog.Err(err2))
+ }
+ })
s.htmlTemplateWatcher = htmlTemplateWatcher
}
@@ -865,13 +877,10 @@ func (s *Server) Shutdown() {
// Push notification hub needs to be shutdown after HTTP server
// to prevent stray requests from generating a push notification after it's shut down.
s.StopPushNotificationsHubWorkers()
+ s.htmlTemplateWatcher.Close()
s.WaitForGoroutines()
- if s.htmlTemplateWatcher != nil {
- s.htmlTemplateWatcher.Close()
- }
-
if s.advancedLogListenerCleanup != nil {
s.advancedLogListenerCleanup()
s.advancedLogListenerCleanup = nil
diff --git a/cmd/mattermost/commands/cmdtestlib.go b/cmd/mattermost/commands/cmdtestlib.go
index d936d1f473..3f202a1feb 100644
--- a/cmd/mattermost/commands/cmdtestlib.go
+++ b/cmd/mattermost/commands/cmdtestlib.go
@@ -38,7 +38,7 @@ type testHelper struct {
// Setup creates an instance of testHelper.
func Setup(t testing.TB) *testHelper {
- dir, err := ioutil.TempDir("", "testHelper")
+ dir, err := testlib.SetupTestResources()
if err != nil {
panic("failed to create temporary directory: " + err.Error())
}
@@ -60,7 +60,7 @@ func Setup(t testing.TB) *testHelper {
// Setup creates an instance of testHelper.
func SetupWithStoreMock(t testing.TB) *testHelper {
- dir, err := ioutil.TempDir("", "testHelper")
+ dir, err := testlib.SetupTestResources()
if err != nil {
panic("failed to create temporary directory: " + err.Error())
}
diff --git a/cmd/mattermost/commands/config_flag_test.go b/cmd/mattermost/commands/config_flag_test.go
index 5104fa57c4..6c2d6a0427 100644
--- a/cmd/mattermost/commands/config_flag_test.go
+++ b/cmd/mattermost/commands/config_flag_test.go
@@ -9,9 +9,6 @@ import (
"testing"
"github.com/stretchr/testify/require"
-
- "github.com/mattermost/mattermost-server/v5/utils"
- "github.com/mattermost/mattermost-server/v5/utils/fileutils"
)
func TestConfigFlag(t *testing.T) {
@@ -19,16 +16,14 @@ func TestConfigFlag(t *testing.T) {
defer th.TearDown()
dir := th.TemporaryDirectory()
- i18n, ok := fileutils.FindDir("i18n")
- require.True(t, ok)
- require.NoError(t, utils.CopyDir(i18n, filepath.Join(dir, "i18n")))
-
prevDir, err := os.Getwd()
require.NoError(t, err)
defer os.Chdir(prevDir)
os.Chdir(dir)
t.Run("version without a config file should fail", func(t *testing.T) {
+ err := os.RemoveAll("config")
+ require.NoError(t, err)
th.SetAutoConfig(false)
defer th.SetAutoConfig(true)
require.Error(t, th.RunCommand(t, "version"))
diff --git a/shared/templates/templates.go b/shared/templates/templates.go
new file mode 100644
index 0000000000..12ec85b766
--- /dev/null
+++ b/shared/templates/templates.go
@@ -0,0 +1,143 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+package templates
+
+import (
+ "bytes"
+ "html/template"
+ "io"
+ "path/filepath"
+ "sync"
+
+ "github.com/fsnotify/fsnotify"
+)
+
+// Container represents a set of templates that can be render
+type Container struct {
+ templates *template.Template
+ mutex sync.RWMutex
+ stop chan struct{}
+ stopped chan struct{}
+ watch bool
+}
+
+// Data contains the data used to populate the template variables, it has Props
+// that can be of any type and HTML that only can be `template.HTML` types.
+type Data struct {
+ Props map[string]interface{}
+ HTML map[string]template.HTML
+}
+
+// NewFromTemplates creates a new templates container using a
+// `template.Template` object
+func NewFromTemplate(templates *template.Template) *Container {
+ return &Container{templates: templates}
+}
+
+// New creates a new templates container scanning a directory.
+func New(directory string) (*Container, error) {
+ c := &Container{}
+
+ htmlTemplates, err := template.ParseGlob(filepath.Join(directory, "*.html"))
+ if err != nil {
+ return nil, err
+ }
+ c.templates = htmlTemplates
+
+ return c, nil
+}
+
+// NewWithWatcher creates a new templates container scanning a directory and
+// watch the directory filesystem changes to apply them to the loaded
+// templates. This function returns the container and an errors channel to pass
+// all errors that can happen during the watch process, or an regular error if
+// we fail to create the templates or the watcher. The caller must consume the
+// returned errors channel to ensure not blocking the watch process.
+func NewWithWatcher(directory string) (*Container, <-chan error, error) {
+ htmlTemplates, err := template.ParseGlob(filepath.Join(directory, "*.html"))
+ if err != nil {
+ return nil, nil, err
+ }
+
+ watcher, err := fsnotify.NewWatcher()
+ if err != nil {
+ return nil, nil, err
+ }
+
+ err = watcher.Add(directory)
+ if err != nil {
+ watcher.Close()
+ return nil, nil, err
+ }
+
+ c := &Container{
+ templates: htmlTemplates,
+ watch: true,
+ stop: make(chan struct{}),
+ stopped: make(chan struct{}),
+ }
+ errors := make(chan error)
+
+ go func() {
+ defer close(errors)
+ defer close(c.stopped)
+ defer watcher.Close()
+
+ for {
+ select {
+ case <-c.stop:
+ return
+ case event := <-watcher.Events:
+ if event.Op&fsnotify.Write == fsnotify.Write {
+ if htmlTemplates, err := template.ParseGlob(filepath.Join(directory, "*.html")); err != nil {
+ errors <- err
+ } else {
+ c.mutex.Lock()
+ c.templates = htmlTemplates
+ c.mutex.Unlock()
+ }
+ }
+ case err := <-watcher.Errors:
+ errors <- err
+ }
+ }
+ }()
+
+ return c, errors, nil
+}
+
+// Close stops the templates watcher of the container in case you have created
+// it with watch parameter set to true
+func (c *Container) Close() {
+ c.mutex.RLock()
+ defer c.mutex.RUnlock()
+ if c.watch {
+ close(c.stop)
+ <-c.stopped
+ }
+}
+
+// RenderToString renders the template referenced with the template name using
+// the data provided and return a string with the result
+func (c *Container) RenderToString(templateName string, data Data) (string, error) {
+ var text bytes.Buffer
+ if err := c.Render(&text, templateName, data); err != nil {
+ return "", err
+ }
+ return text.String(), nil
+}
+
+// RenderToString renders the template referenced with the template name using
+// the data provided and write it to the writer provided
+func (c *Container) Render(w io.Writer, templateName string, data Data) error {
+ c.mutex.RLock()
+ htmlTemplates := c.templates
+ c.mutex.RUnlock()
+
+ if err := htmlTemplates.ExecuteTemplate(w, templateName, data); err != nil {
+ return err
+ }
+
+ return nil
+}
diff --git a/shared/templates/templates_test.go b/shared/templates/templates_test.go
new file mode 100644
index 0000000000..40940e1a03
--- /dev/null
+++ b/shared/templates/templates_test.go
@@ -0,0 +1,115 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+package templates
+
+import (
+ "bytes"
+ "html/template"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestHTMLTemplateWatcher(t *testing.T) {
+ dir, err := ioutil.TempDir("", "")
+ require.NoError(t, err)
+ defer os.RemoveAll(dir)
+
+ require.NoError(t, os.Mkdir(filepath.Join(dir, "templates"), 0700))
+ require.NoError(t, ioutil.WriteFile(filepath.Join(dir, "templates", "foo.html"), []byte(`{{ define "foo" }}foo{{ end }}`), 0600))
+
+ prevDir, err := os.Getwd()
+ require.NoError(t, err)
+ defer os.Chdir(prevDir)
+ os.Chdir(dir)
+
+ watcher, errChan, err := NewWithWatcher("templates")
+ require.NoError(t, err)
+ require.NotNil(t, watcher)
+ select {
+ case msg := <-errChan:
+ err = msg
+ default:
+ err = nil
+ }
+ require.NoError(t, err)
+ defer watcher.Close()
+
+ text, err := watcher.RenderToString("foo", Data{})
+ require.NoError(t, err)
+ assert.Equal(t, "foo", text)
+
+ require.NoError(t, ioutil.WriteFile(filepath.Join(dir, "templates", "foo.html"), []byte(`{{ define "foo" }}bar{{ end }}`), 0600))
+
+ require.Eventually(t, func() bool {
+ text, err := watcher.RenderToString("foo", Data{})
+ return text == "bar" && err == nil
+ }, time.Millisecond*1000, time.Millisecond*50)
+}
+
+func TestNewWithWatcher_BadDirectory(t *testing.T) {
+ watcher, errChan, err := NewWithWatcher("notarealdirectory")
+ require.Error(t, err)
+ assert.Nil(t, watcher)
+ assert.Nil(t, errChan)
+}
+
+func TestNew_BadDirectory(t *testing.T) {
+ watcher, err := New("notarealdirectory")
+ assert.Nil(t, watcher)
+ assert.Error(t, err)
+}
+
+func TestRender(t *testing.T) {
+ tpl := template.New("test")
+ _, err := tpl.Parse(`{{ define "foo" }}foo{{ .Props.Bar }}{{ end }}`)
+ require.NoError(t, err)
+ mt := NewFromTemplate(tpl)
+
+ data := Data{
+ Props: map[string]interface{}{
+ "Bar": "bar",
+ },
+ }
+ text, err := mt.RenderToString("foo", data)
+ require.NoError(t, err)
+ assert.Equal(t, "foobar", text)
+
+ buf := &bytes.Buffer{}
+ require.NoError(t, mt.Render(buf, "foo", data))
+ assert.Equal(t, "foobar", buf.String())
+}
+
+func TestRenderError(t *testing.T) {
+ tpl := template.New("test")
+ _, err := tpl.Parse(`{{ define "foo" }}foo{{ .Foo.Bar }}bar{{ end }}`)
+ require.NoError(t, err)
+ mt := NewFromTemplate(tpl)
+
+ text, err := mt.RenderToString("foo", Data{})
+ require.Error(t, err)
+ assert.Equal(t, "", text)
+
+ buf := &bytes.Buffer{}
+ assert.Error(t, mt.Render(buf, "foo", Data{}))
+ assert.Equal(t, "foo", buf.String())
+}
+
+func TestRenderUnknownTemplate(t *testing.T) {
+ tpl := template.New("")
+ mt := NewFromTemplate(tpl)
+
+ text, err := mt.RenderToString("foo", Data{})
+ require.Error(t, err)
+ assert.Equal(t, "", text)
+
+ buf := &bytes.Buffer{}
+ assert.Error(t, mt.Render(buf, "foo", Data{}))
+ assert.Equal(t, "", buf.String())
+}
diff --git a/testlib/resources.go b/testlib/resources.go
index 63fd347d17..a0757f3a17 100644
--- a/testlib/resources.go
+++ b/testlib/resources.go
@@ -87,6 +87,7 @@ func getTestResourcesToSetup() []testResourceDetails {
var testResourcesToSetup = []testResourceDetails{
{root, "mattermost-server", resourceTypeFolder, actionSymlink},
+ {"go.mod", "go.mod", resourceTypeFile, actionSymlink},
{"i18n", "i18n", resourceTypeFolder, actionSymlink},
{"templates", "templates", resourceTypeFolder, actionSymlink},
{"tests", "tests", resourceTypeFolder, actionSymlink},
diff --git a/utils/html.go b/utils/html.go
deleted file mode 100644
index 17ba46b7b2..0000000000
--- a/utils/html.go
+++ /dev/null
@@ -1,118 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See LICENSE.txt for license information.
-
-package utils
-
-import (
- "bytes"
- "errors"
- "html/template"
- "io"
- "path/filepath"
- "sync/atomic"
-
- "github.com/fsnotify/fsnotify"
-
- "github.com/mattermost/mattermost-server/v5/shared/mlog"
- "github.com/mattermost/mattermost-server/v5/utils/fileutils"
-)
-
-type HTMLTemplateWatcher struct {
- templates atomic.Value
- stop chan struct{}
- stopped chan struct{}
-}
-
-func NewHTMLTemplateWatcher(directory string) (*HTMLTemplateWatcher, error) {
- templatesDir, _ := fileutils.FindDir(directory)
- mlog.Debug("Parsing server templates", mlog.String("templates_directory", templatesDir))
-
- ret := &HTMLTemplateWatcher{
- stop: make(chan struct{}),
- stopped: make(chan struct{}),
- }
-
- watcher, err := fsnotify.NewWatcher()
- if err != nil {
- return nil, err
- }
-
- if err = watcher.Add(templatesDir); err != nil {
- return nil, err
- }
-
- htmlTemplates, err := template.ParseGlob(filepath.Join(templatesDir, "*.html"))
- if err != nil {
- return nil, err
- }
- ret.templates.Store(htmlTemplates)
-
- go func() {
- defer close(ret.stopped)
- defer watcher.Close()
-
- for {
- select {
- case <-ret.stop:
- return
- case event := <-watcher.Events:
- if event.Op&fsnotify.Write == fsnotify.Write {
- mlog.Info("Re-parsing templates because of modified file", mlog.String("file_name", event.Name))
- if htmlTemplates, err := template.ParseGlob(filepath.Join(templatesDir, "*.html")); err != nil {
- mlog.Error("Failed to parse templates.", mlog.Err(err))
- } else {
- ret.templates.Store(htmlTemplates)
- }
- }
- case err := <-watcher.Errors:
- mlog.Error("Failed in directory watcher", mlog.Err(err))
- }
- }
- }()
-
- return ret, nil
-}
-
-func (w *HTMLTemplateWatcher) Templates() *template.Template {
- return w.templates.Load().(*template.Template)
-}
-
-func (w *HTMLTemplateWatcher) Close() {
- close(w.stop)
- <-w.stopped
-}
-
-type HTMLTemplate struct {
- Templates *template.Template
- TemplateName string
- Props map[string]interface{}
- HTML map[string]template.HTML
-}
-
-func NewHTMLTemplate(templates *template.Template, templateName string) *HTMLTemplate {
- return &HTMLTemplate{
- Templates: templates,
- TemplateName: templateName,
- Props: make(map[string]interface{}),
- HTML: make(map[string]template.HTML),
- }
-}
-
-func (t *HTMLTemplate) Render() string {
- var text bytes.Buffer
- t.RenderToWriter(&text)
- return text.String()
-}
-
-func (t *HTMLTemplate) RenderToWriter(w io.Writer) error {
- if t.Templates == nil {
- return errors.New("no html templates")
- }
-
- if err := t.Templates.ExecuteTemplate(w, t.TemplateName, t); err != nil {
- mlog.Warn("Error rendering template", mlog.String("template_name", t.TemplateName), mlog.Err(err))
- return err
- }
-
- return nil
-}
diff --git a/utils/html_test.go b/utils/html_test.go
deleted file mode 100644
index 07935797cb..0000000000
--- a/utils/html_test.go
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
-// See LICENSE.txt for license information.
-
-package utils
-
-import (
- "bytes"
- "html/template"
- "io/ioutil"
- "os"
- "path/filepath"
- "testing"
- "time"
-
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-func TestHTMLTemplateWatcher(t *testing.T) {
- TranslationsPreInit()
-
- dir, err := ioutil.TempDir("", "")
- require.NoError(t, err)
- defer os.RemoveAll(dir)
-
- require.NoError(t, os.Mkdir(filepath.Join(dir, "templates"), 0700))
- require.NoError(t, ioutil.WriteFile(filepath.Join(dir, "templates", "foo.html"), []byte(`{{ define "foo" }}foo{{ end }}`), 0600))
-
- prevDir, err := os.Getwd()
- require.NoError(t, err)
- defer os.Chdir(prevDir)
- os.Chdir(dir)
-
- watcher, err := NewHTMLTemplateWatcher("templates")
- require.NotNil(t, watcher)
- require.NoError(t, err)
- defer watcher.Close()
-
- tpl := NewHTMLTemplate(watcher.Templates(), "foo")
- assert.Equal(t, "foo", tpl.Render())
-
- require.NoError(t, ioutil.WriteFile(filepath.Join(dir, "templates", "foo.html"), []byte(`{{ define "foo" }}bar{{ end }}`), 0600))
-
- for i := 0; i < 30; i++ {
- tpl = NewHTMLTemplate(watcher.Templates(), "foo")
- if tpl.Render() == "bar" {
- break
- }
- time.Sleep(time.Millisecond * 50)
- }
- assert.Equal(t, "bar", tpl.Render())
-}
-
-func TestHTMLTemplateWatcher_BadDirectory(t *testing.T) {
- TranslationsPreInit()
- watcher, err := NewHTMLTemplateWatcher("notarealdirectory")
- assert.Nil(t, watcher)
- assert.Error(t, err)
-}
-
-func TestHTMLTemplate(t *testing.T) {
- tpl := template.New("test")
- _, err := tpl.Parse(`{{ define "foo" }}foo{{ .Props.Bar }}{{ end }}`)
- require.NoError(t, err)
-
- htmlTemplate := NewHTMLTemplate(tpl, "foo")
- htmlTemplate.Props["Bar"] = "bar"
- assert.Equal(t, "foobar", htmlTemplate.Render())
-
- buf := &bytes.Buffer{}
- require.NoError(t, htmlTemplate.RenderToWriter(buf))
- assert.Equal(t, "foobar", buf.String())
-}
-
-func TestHTMLTemplate_RenderError(t *testing.T) {
- tpl := template.New("test")
- _, err := tpl.Parse(`{{ define "foo" }}foo{{ .Foo.Bar }}bar{{ end }}`)
- require.NoError(t, err)
-
- htmlTemplate := NewHTMLTemplate(tpl, "foo")
- assert.Equal(t, "foo", htmlTemplate.Render())
-
- buf := &bytes.Buffer{}
- assert.Error(t, htmlTemplate.RenderToWriter(buf))
- assert.Equal(t, "foo", buf.String())
-}
diff --git a/web/unsupported_browser.go b/web/unsupported_browser.go
index 695a2b2443..5463f17d26 100644
--- a/web/unsupported_browser.go
+++ b/web/unsupported_browser.go
@@ -9,7 +9,7 @@ import (
"github.com/avct/uasurfer"
"github.com/mattermost/mattermost-server/v5/app"
- "github.com/mattermost/mattermost-server/v5/utils"
+ "github.com/mattermost/mattermost-server/v5/shared/templates"
)
// MattermostApp describes downloads for the Mattermost App
@@ -46,7 +46,13 @@ type SystemBrowser struct {
func renderUnsupportedBrowser(app app.AppIface, w http.ResponseWriter, r *http.Request) {
w.Header().Set("Cache-Control", "no-store")
- page := utils.NewHTMLTemplate(app.Srv().HTMLTemplates(), "unsupported_browser")
+
+ data := templates.Data{
+ Props: map[string]interface{}{
+ "DownloadAppOrUpgradeBrowserString": app.T("web.error.unsupported_browser.download_app_or_upgrade_browser"),
+ "LearnMoreString": app.T("web.error.unsupported_browser.learn_more"),
+ },
+ }
// User Agent info
ua := uasurfer.Parse(r.UserAgent())
@@ -57,18 +63,16 @@ func renderUnsupportedBrowser(app app.AppIface, w http.ResponseWriter, r *http.R
// Basic heading translations
if isSafari {
- page.Props["NoLongerSupportString"] = app.T("web.error.unsupported_browser.no_longer_support_version")
+ data.Props["NoLongerSupportString"] = app.T("web.error.unsupported_browser.no_longer_support_version")
} else {
- page.Props["NoLongerSupportString"] = app.T("web.error.unsupported_browser.no_longer_support")
+ data.Props["NoLongerSupportString"] = app.T("web.error.unsupported_browser.no_longer_support")
}
- page.Props["DownloadAppOrUpgradeBrowserString"] = app.T("web.error.unsupported_browser.download_app_or_upgrade_browser")
- page.Props["LearnMoreString"] = app.T("web.error.unsupported_browser.learn_more")
// Mattermost app version
if isWindows {
- page.Props["App"] = renderMattermostAppWindows(app)
+ data.Props["App"] = renderMattermostAppWindows(app)
} else if isMacOSX {
- page.Props["App"] = renderMattermostAppMac(app)
+ data.Props["App"] = renderMattermostAppMac(app)
}
// Browsers to download
@@ -78,14 +82,14 @@ func renderUnsupportedBrowser(app app.AppIface, w http.ResponseWriter, r *http.R
if isSafari {
browsers = append(browsers, renderBrowserSafari(app))
}
- page.Props["Browsers"] = browsers
+ data.Props["Browsers"] = browsers
// If on Windows 10, show link to Edge
if isWindows10 {
- page.Props["SystemBrowser"] = renderSystemBrowserEdge(app, r)
+ data.Props["SystemBrowser"] = renderSystemBrowserEdge(app, r)
}
- page.RenderToWriter(w)
+ app.Srv().TemplatesContainer().Render(w, "unsupported_browser", data)
}
func renderMattermostAppMac(app app.AppIface) MattermostApp {