Extracting html templates into a library (#16946)

* Extracting html templates into a library

* Moving tests to the right place

* Fixing tests

* Addressing PR review comments

* Addressing PR review comments

* Replacing attomic with RWMutex

* Returning errors as channel for Templates watcher

* Address PR review comments

* Other small fixes

* Simplifying NewWithWatcher

* Addressing PR review comments

* Making error handling on rendering templates more robust

* Fixing tests

* Changing how we return errors

* Fixing shadow variables

* Addressing PR review comments

* Logging errors from the outside of sendNotificationEmail

* Fixing lock in shutdown

* Fixing the resource copy for commands tests temporary directories

* Removing unused import

* A couple of tiny fixes
Этот коммит содержится в:
Jesús Espino
2021-03-12 18:46:43 +01:00
коммит произвёл GitHub
родитель 58dce5930e
Коммит 95b0809850
16 изменённых файлов: 834 добавлений и 604 удалений

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

@@ -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)
}
}

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

@@ -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)
}

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

@@ -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)
}

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

@@ -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.")
}

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

@@ -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))
}
}
}
}

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

@@ -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 {

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

@@ -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, "<a href='"+channelURL+"'>"+mention+"</a>")
@@ -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, "<a href='"+channelURL+"'>"+mention+"</a>")
@@ -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))
}

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

@@ -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