mirror of
https://github.com/mattermost/mattermost.git
synced 2026-02-18 18:18:23 -05:00
[MM-64840] Add EmailNotificationWillBeSent Plugin Hook (#33421)
This commit is contained in:
parent
98ad2adb06
commit
c0ff672afb
10 changed files with 796 additions and 297 deletions
|
|
@ -417,19 +417,21 @@ func (a *App) SendNotifications(c request.CTX, post *model.Post, team *model.Tea
|
|||
if err != nil {
|
||||
c.Logger().Warn("Unable to get the sender user profile image.", mlog.String("user_id", sender.Id), mlog.Err(err))
|
||||
}
|
||||
if err := a.sendNotificationEmail(c, notification, profileMap[id], team, senderProfileImage); err != nil {
|
||||
a.CountNotificationReason(model.NotificationStatusError, model.NotificationTypeEmail, model.NotificationReasonEmailSendError, model.NotificationNoPlatform)
|
||||
a.NotificationsLog().Error("Error sending email notification",
|
||||
mlog.String("type", model.NotificationTypeEmail),
|
||||
mlog.String("post_id", post.Id),
|
||||
mlog.String("status", model.NotificationStatusError),
|
||||
mlog.String("reason", model.NotificationReasonEmailSendError),
|
||||
mlog.String("sender_id", sender.Id),
|
||||
mlog.String("receiver_id", id),
|
||||
mlog.Err(err),
|
||||
)
|
||||
c.Logger().Warn("Unable to send notification email.", mlog.Err(err))
|
||||
}
|
||||
a.Srv().Go(func() {
|
||||
if _, err := a.sendNotificationEmail(c, notification, profileMap[id], team, senderProfileImage); err != nil {
|
||||
a.CountNotificationReason(model.NotificationStatusError, model.NotificationTypeEmail, model.NotificationReasonEmailSendError, model.NotificationNoPlatform)
|
||||
a.NotificationsLog().Error("Error sending email notification",
|
||||
mlog.String("type", model.NotificationTypeEmail),
|
||||
mlog.String("post_id", post.Id),
|
||||
mlog.String("status", model.NotificationStatusError),
|
||||
mlog.String("reason", model.NotificationReasonEmailSendError),
|
||||
mlog.String("sender_id", sender.Id),
|
||||
mlog.String("receiver_id", id),
|
||||
mlog.Err(err),
|
||||
)
|
||||
c.Logger().Warn("Unable to send notification email.", mlog.Err(err))
|
||||
}
|
||||
})
|
||||
} else {
|
||||
a.NotificationsLog().Debug("Email disallowed by user",
|
||||
mlog.String("type", model.NotificationTypeEmail),
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import (
|
|||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/mattermost/mattermost/server/public/model"
|
||||
"github.com/mattermost/mattermost/server/public/plugin"
|
||||
"github.com/mattermost/mattermost/server/public/shared/i18n"
|
||||
"github.com/mattermost/mattermost/server/public/shared/mlog"
|
||||
"github.com/mattermost/mattermost/server/public/shared/request"
|
||||
|
|
@ -20,14 +21,134 @@ import (
|
|||
"github.com/mattermost/mattermost/server/v8/channels/utils"
|
||||
)
|
||||
|
||||
func (a *App) sendNotificationEmail(c request.CTX, notification *PostNotification, user *model.User, team *model.Team, senderProfileImage []byte) error {
|
||||
func (a *App) buildEmailNotification(
|
||||
ctx request.CTX,
|
||||
notification *PostNotification,
|
||||
user *model.User,
|
||||
team *model.Team,
|
||||
) *model.EmailNotification {
|
||||
channel := notification.Channel
|
||||
post := notification.Post
|
||||
sender := notification.Sender
|
||||
|
||||
translateFunc := i18n.GetUserTranslations(user.Locale)
|
||||
nameFormat := a.GetNotificationNameFormat(user)
|
||||
|
||||
var useMilitaryTime bool
|
||||
if data, err := a.Srv().Store().Preference().Get(
|
||||
user.Id, model.PreferenceCategoryDisplaySettings, model.PreferenceNameUseMilitaryTime,
|
||||
); err != nil {
|
||||
ctx.Logger().Debug("Failed to retrieve user military time preference, defaulting to false",
|
||||
mlog.String("user_id", user.Id), mlog.Err(err))
|
||||
useMilitaryTime = false
|
||||
} else {
|
||||
useMilitaryTime = data.Value == "true"
|
||||
}
|
||||
|
||||
channelName := notification.GetChannelName(nameFormat, "")
|
||||
senderName := notification.GetSenderName(nameFormat,
|
||||
*a.Config().ServiceSettings.EnablePostUsernameOverride)
|
||||
|
||||
emailNotificationContentsType := model.EmailNotificationContentsFull
|
||||
if license := a.Srv().License(); license != nil && *license.Features.EmailNotificationContents {
|
||||
emailNotificationContentsType = *a.Config().EmailSettings.EmailNotificationContentsType
|
||||
}
|
||||
|
||||
var subject string
|
||||
if channel.Type == model.ChannelTypeDirect {
|
||||
subject = getDirectMessageNotificationEmailSubject(
|
||||
user, post, translateFunc, *a.Config().TeamSettings.SiteName, senderName, useMilitaryTime)
|
||||
} else if channel.Type == model.ChannelTypeGroup {
|
||||
subject = getGroupMessageNotificationEmailSubject(
|
||||
user, post, translateFunc, *a.Config().TeamSettings.SiteName, channelName, emailNotificationContentsType, useMilitaryTime)
|
||||
} else if *a.Config().EmailSettings.UseChannelInEmailNotifications {
|
||||
subject = getNotificationEmailSubject(
|
||||
user, post, translateFunc, *a.Config().TeamSettings.SiteName, team.DisplayName+" ("+channelName+")", useMilitaryTime)
|
||||
} else {
|
||||
subject = getNotificationEmailSubject(
|
||||
user, post, translateFunc, *a.Config().TeamSettings.SiteName, team.DisplayName, useMilitaryTime)
|
||||
}
|
||||
|
||||
var title, subtitle string
|
||||
if channel.Type == model.ChannelTypeDirect {
|
||||
title = translateFunc("app.notification.body.dm.title", map[string]any{"SenderName": senderName})
|
||||
subtitle = translateFunc("app.notification.body.dm.subTitle", map[string]any{"SenderName": senderName})
|
||||
} else if channel.Type == model.ChannelTypeGroup {
|
||||
title = translateFunc("app.notification.body.group.title", map[string]any{"SenderName": senderName})
|
||||
subtitle = translateFunc("app.notification.body.group.subTitle", map[string]any{"SenderName": senderName})
|
||||
} else {
|
||||
title = translateFunc("app.notification.body.mention.title", map[string]any{"SenderName": senderName})
|
||||
subtitle = translateFunc("app.notification.body.mention.subTitle", map[string]any{"SenderName": senderName, "ChannelName": channelName})
|
||||
}
|
||||
|
||||
if a.IsCRTEnabledForUser(ctx, user.Id) && post.RootId != "" {
|
||||
title = translateFunc("app.notification.body.thread.title", map[string]any{"SenderName": senderName})
|
||||
if channel.Type == model.ChannelTypeDirect {
|
||||
subtitle = translateFunc("app.notification.body.thread_dm.subTitle", map[string]any{"SenderName": senderName})
|
||||
} else if channel.Type == model.ChannelTypeGroup {
|
||||
subtitle = translateFunc("app.notification.body.thread_gm.subTitle", map[string]any{"SenderName": senderName})
|
||||
} else if emailNotificationContentsType == model.EmailNotificationContentsFull {
|
||||
subtitle = translateFunc("app.notification.body.thread_channel_full.subTitle", map[string]any{"SenderName": senderName, "ChannelName": channelName})
|
||||
} else {
|
||||
subtitle = translateFunc("app.notification.body.thread_channel.subTitle", map[string]any{"SenderName": senderName})
|
||||
}
|
||||
}
|
||||
|
||||
var messageHTML, messageText string
|
||||
if emailNotificationContentsType == model.EmailNotificationContentsFull {
|
||||
messageHTML = a.GetMessageForNotification(post, team.Name, a.GetSiteURL(), translateFunc)
|
||||
messageText = post.Message
|
||||
}
|
||||
|
||||
landingURL := a.GetSiteURL() + "/landing#/" + team.Name
|
||||
buttonURL := landingURL
|
||||
if team.Name != "select_team" {
|
||||
buttonURL = landingURL + "/pl/" + post.Id
|
||||
}
|
||||
|
||||
return &model.EmailNotification{
|
||||
// Core identifiers (immutable)
|
||||
PostId: post.Id,
|
||||
ChannelId: channel.Id,
|
||||
TeamId: team.Id,
|
||||
SenderId: sender.Id,
|
||||
SenderDisplayName: senderName,
|
||||
RecipientId: user.Id,
|
||||
RootId: post.RootId,
|
||||
|
||||
// Context for plugin decision-making (immutable)
|
||||
ChannelType: string(channel.Type),
|
||||
ChannelName: channelName,
|
||||
TeamName: team.DisplayName,
|
||||
SenderUsername: sender.Username,
|
||||
IsDirectMessage: channel.Type == model.ChannelTypeDirect,
|
||||
IsGroupMessage: channel.Type == model.ChannelTypeGroup,
|
||||
IsThreadReply: post.RootId != "",
|
||||
IsCRTEnabled: a.IsCRTEnabledForUser(ctx, user.Id),
|
||||
UseMilitaryTime: useMilitaryTime,
|
||||
|
||||
// Customizable content fields
|
||||
EmailNotificationContent: model.EmailNotificationContent{
|
||||
Subject: subject,
|
||||
Title: title,
|
||||
SubTitle: subtitle,
|
||||
MessageHTML: messageHTML,
|
||||
MessageText: messageText,
|
||||
ButtonText: translateFunc("api.templates.post_body.button"),
|
||||
ButtonURL: buttonURL,
|
||||
FooterText: translateFunc("app.notification.footer.title"),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (a *App) sendNotificationEmail(c request.CTX, notification *PostNotification, user *model.User, team *model.Team, senderProfileImage []byte) (*model.EmailNotification, error) {
|
||||
channel := notification.Channel
|
||||
post := notification.Post
|
||||
|
||||
if channel.IsGroupOrDirect() {
|
||||
teams, err := a.Srv().Store().Team().GetTeamsByUserId(user.Id)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to get user teams")
|
||||
return nil, errors.Wrap(err, "unable to get user teams")
|
||||
}
|
||||
|
||||
// if the recipient isn't in the current user's team, just pick one
|
||||
|
|
@ -48,6 +169,41 @@ func (a *App) sendNotificationEmail(c request.CTX, notification *PostNotificatio
|
|||
}
|
||||
}
|
||||
|
||||
// Create EmailNotification object for plugin customization
|
||||
emailNotification := a.buildEmailNotification(c, notification, user, team)
|
||||
|
||||
// Call plugin hook to allow customization of emailNotification
|
||||
rejectionReason := ""
|
||||
a.ch.RunMultiHook(func(hooks plugin.Hooks, manifest *model.Manifest) bool {
|
||||
var replacementContent *model.EmailNotificationContent
|
||||
replacementContent, rejectionReason = hooks.EmailNotificationWillBeSent(emailNotification)
|
||||
if rejectionReason != "" {
|
||||
c.Logger().Info("Email notification cancelled by plugin.",
|
||||
mlog.String("rejection_reason", rejectionReason),
|
||||
mlog.String("plugin_id", manifest.Id),
|
||||
mlog.String("plugin_name", manifest.Name))
|
||||
return false
|
||||
}
|
||||
if replacementContent != nil {
|
||||
emailNotification.EmailNotificationContent = *replacementContent
|
||||
}
|
||||
return true
|
||||
}, plugin.EmailNotificationWillBeSentID)
|
||||
|
||||
if rejectionReason != "" {
|
||||
// Email notification rejected by plugin
|
||||
a.CountNotificationReason(model.NotificationStatusNotSent, model.NotificationTypeEmail, model.NotificationReasonRejectedByPlugin, model.NotificationNoPlatform)
|
||||
a.NotificationsLog().Debug("Email notification rejected by plugin",
|
||||
mlog.String("type", model.NotificationTypeEmail),
|
||||
mlog.String("status", model.NotificationStatusNotSent),
|
||||
mlog.String("reason", model.NotificationReasonRejectedByPlugin),
|
||||
mlog.String("rejection_reason", rejectionReason),
|
||||
mlog.String("user_id", user.Id),
|
||||
mlog.String("post_id", post.Id),
|
||||
)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if *a.Config().EmailSettings.EnableEmailBatching {
|
||||
var sendBatched bool
|
||||
if data, err := a.Srv().Store().Preference().Get(user.Id, model.PreferenceCategoryNotifications, model.PreferenceNameEmailInterval); err != nil {
|
||||
|
|
@ -60,57 +216,27 @@ func (a *App) sendNotificationEmail(c request.CTX, notification *PostNotificatio
|
|||
|
||||
if sendBatched {
|
||||
if err := a.Srv().EmailService.AddNotificationEmailToBatch(user, post, team); err == nil {
|
||||
return nil
|
||||
return emailNotification, nil
|
||||
}
|
||||
}
|
||||
|
||||
// fall back to sending a single email if we can't batch it for some reason
|
||||
}
|
||||
|
||||
translateFunc := i18n.GetUserTranslations(user.Locale)
|
||||
|
||||
var useMilitaryTime bool
|
||||
if data, err := a.Srv().Store().Preference().Get(user.Id, model.PreferenceCategoryDisplaySettings, model.PreferenceNameUseMilitaryTime); err != nil {
|
||||
useMilitaryTime = false
|
||||
} else {
|
||||
useMilitaryTime = data.Value == "true"
|
||||
}
|
||||
|
||||
nameFormat := a.GetNotificationNameFormat(user)
|
||||
|
||||
channelName := notification.GetChannelName(nameFormat, "")
|
||||
senderName := notification.GetSenderName(nameFormat, *a.Config().ServiceSettings.EnablePostUsernameOverride)
|
||||
|
||||
emailNotificationContentsType := model.EmailNotificationContentsFull
|
||||
if license := a.Srv().License(); license != nil && *license.Features.EmailNotificationContents {
|
||||
emailNotificationContentsType = *a.Config().EmailSettings.EmailNotificationContentsType
|
||||
}
|
||||
|
||||
var subjectText string
|
||||
if channel.Type == model.ChannelTypeDirect {
|
||||
subjectText = getDirectMessageNotificationEmailSubject(user, post, translateFunc, *a.Config().TeamSettings.SiteName, senderName, useMilitaryTime)
|
||||
} else if channel.Type == model.ChannelTypeGroup {
|
||||
subjectText = getGroupMessageNotificationEmailSubject(user, post, translateFunc, *a.Config().TeamSettings.SiteName, channelName, emailNotificationContentsType, useMilitaryTime)
|
||||
} else if *a.Config().EmailSettings.UseChannelInEmailNotifications {
|
||||
subjectText = getNotificationEmailSubject(user, post, translateFunc, *a.Config().TeamSettings.SiteName, team.DisplayName+" ("+channelName+")", useMilitaryTime)
|
||||
} else {
|
||||
subjectText = getNotificationEmailSubject(user, post, translateFunc, *a.Config().TeamSettings.SiteName, team.DisplayName, useMilitaryTime)
|
||||
}
|
||||
|
||||
// Handle sender photo
|
||||
senderPhoto := ""
|
||||
embeddedFiles := make(map[string]io.Reader)
|
||||
if emailNotificationContentsType == model.EmailNotificationContentsFull && senderProfileImage != nil {
|
||||
if emailNotification.MessageHTML != "" && senderProfileImage != nil {
|
||||
senderPhoto = "user-avatar.png"
|
||||
embeddedFiles = map[string]io.Reader{
|
||||
senderPhoto: bytes.NewReader(senderProfileImage),
|
||||
}
|
||||
}
|
||||
|
||||
landingURL := a.GetSiteURL() + "/landing#/" + team.Name
|
||||
|
||||
var bodyText, err = a.getNotificationEmailBody(c, user, post, channel, channelName, senderName, team.Name, landingURL, emailNotificationContentsType, useMilitaryTime, translateFunc, senderPhoto)
|
||||
// Build email body using EmailNotification data
|
||||
var bodyText, err = a.getNotificationEmailBodyFromEmailNotification(c, user, emailNotification, post, senderPhoto)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to render the email notification template")
|
||||
return nil, errors.Wrap(err, "unable to render the email notification template")
|
||||
}
|
||||
|
||||
templateString := "<%s@" + utils.GetHostnameFromSiteURL(a.GetSiteURL()) + ">"
|
||||
|
|
@ -118,18 +244,18 @@ func (a *App) sendNotificationEmail(c request.CTX, notification *PostNotificatio
|
|||
inReplyTo := ""
|
||||
references := ""
|
||||
|
||||
if post.Id != "" {
|
||||
messageID = fmt.Sprintf(templateString, post.Id)
|
||||
if emailNotification.PostId != "" {
|
||||
messageID = fmt.Sprintf(templateString, emailNotification.PostId)
|
||||
}
|
||||
|
||||
if post.RootId != "" {
|
||||
referencesVal := fmt.Sprintf(templateString, post.RootId)
|
||||
if emailNotification.RootId != "" {
|
||||
referencesVal := fmt.Sprintf(templateString, emailNotification.RootId)
|
||||
inReplyTo = referencesVal
|
||||
references = referencesVal
|
||||
}
|
||||
|
||||
a.Srv().Go(func() {
|
||||
if nErr := a.Srv().EmailService.SendMailWithEmbeddedFiles(user.Email, html.UnescapeString(subjectText), bodyText, embeddedFiles, messageID, inReplyTo, references, "Notification"); nErr != nil {
|
||||
if nErr := a.Srv().EmailService.SendMailWithEmbeddedFiles(user.Email, html.UnescapeString(emailNotification.Subject), bodyText, embeddedFiles, messageID, inReplyTo, references, "Notification"); nErr != nil {
|
||||
c.Logger().Error("Error while sending the email", mlog.String("user_email", user.Email), mlog.Err(nErr))
|
||||
}
|
||||
})
|
||||
|
|
@ -138,7 +264,7 @@ func (a *App) sendNotificationEmail(c request.CTX, notification *PostNotificatio
|
|||
a.Metrics().IncrementPostSentEmail()
|
||||
}
|
||||
|
||||
return nil
|
||||
return emailNotification, nil
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -214,80 +340,53 @@ type postData struct {
|
|||
MessageAttachments []*email.EmailMessageAttachment
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the email body for notification messages
|
||||
*/
|
||||
func (a *App) getNotificationEmailBody(c request.CTX, recipient *model.User, post *model.Post, channel *model.Channel, channelName string, senderName string, teamName string, landingURL string, emailNotificationContentsType string, useMilitaryTime bool, translateFunc i18n.TranslateFunc, senderPhoto string) (string, error) {
|
||||
func (a *App) GetMessageForNotification(post *model.Post, teamName, siteUrl string, translateFunc i18n.TranslateFunc) string {
|
||||
return a.Srv().EmailService.GetMessageForNotification(post, teamName, siteUrl, translateFunc)
|
||||
}
|
||||
|
||||
func (a *App) getNotificationEmailBodyFromEmailNotification(c request.CTX, recipient *model.User, emailNotification *model.EmailNotification, post *model.Post, senderPhoto string) (string, error) {
|
||||
translateFunc := i18n.GetUserTranslations(recipient.Locale)
|
||||
|
||||
pData := postData{
|
||||
SenderName: truncateUserNames(senderName, 22),
|
||||
SenderName: truncateUserNames(emailNotification.SenderDisplayName, 22),
|
||||
SenderPhoto: senderPhoto,
|
||||
}
|
||||
|
||||
t := utils.GetFormattedPostTime(recipient, post, useMilitaryTime, translateFunc)
|
||||
messageTime := map[string]any{
|
||||
"Hour": t.Hour,
|
||||
"Minute": t.Minute,
|
||||
"TimeZone": t.TimeZone,
|
||||
}
|
||||
if emailNotification.MessageHTML != "" {
|
||||
pData.Message = template.HTML(emailNotification.MessageHTML)
|
||||
|
||||
if emailNotificationContentsType == model.EmailNotificationContentsFull {
|
||||
postMessage := a.GetMessageForNotification(post, teamName, a.GetSiteURL(), translateFunc)
|
||||
pData.Message = template.HTML(postMessage)
|
||||
// Get formatted time for message using the UseMilitaryTime field
|
||||
t := utils.GetFormattedPostTime(recipient, post, emailNotification.UseMilitaryTime, translateFunc)
|
||||
messageTime := map[string]any{
|
||||
"Hour": t.Hour,
|
||||
"Minute": t.Minute,
|
||||
"TimeZone": t.TimeZone,
|
||||
}
|
||||
pData.Time = translateFunc("app.notification.body.dm.time", messageTime)
|
||||
|
||||
// Process message attachments
|
||||
pData.MessageAttachments = email.ProcessMessageAttachments(post, a.GetSiteURL())
|
||||
}
|
||||
|
||||
data := a.Srv().EmailService.NewEmailTemplateData(recipient.Locale)
|
||||
data.Props["SiteURL"] = a.GetSiteURL()
|
||||
if teamName != "select_team" {
|
||||
data.Props["ButtonURL"] = landingURL + "/pl/" + post.Id
|
||||
} else {
|
||||
data.Props["ButtonURL"] = landingURL
|
||||
}
|
||||
|
||||
data.Props["SenderName"] = senderName
|
||||
data.Props["Button"] = translateFunc("api.templates.post_body.button")
|
||||
data.Props["NotificationFooterTitle"] = translateFunc("app.notification.footer.title")
|
||||
data.Props["ButtonURL"] = emailNotification.ButtonURL
|
||||
data.Props["SenderName"] = emailNotification.SenderDisplayName
|
||||
data.Props["Button"] = emailNotification.ButtonText
|
||||
data.Props["NotificationFooterTitle"] = emailNotification.FooterText
|
||||
data.Props["NotificationFooterInfoLogin"] = translateFunc("app.notification.footer.infoLogin")
|
||||
data.Props["NotificationFooterInfo"] = translateFunc("app.notification.footer.info")
|
||||
data.Props["Title"] = emailNotification.Title
|
||||
data.Props["SubTitle"] = emailNotification.SubTitle
|
||||
|
||||
if channel.Type == model.ChannelTypeDirect {
|
||||
// Direct Messages
|
||||
data.Props["Title"] = translateFunc("app.notification.body.dm.title", map[string]any{"SenderName": senderName})
|
||||
data.Props["SubTitle"] = translateFunc("app.notification.body.dm.subTitle", map[string]any{"SenderName": senderName})
|
||||
} else if channel.Type == model.ChannelTypeGroup {
|
||||
// Group Messages
|
||||
data.Props["Title"] = translateFunc("app.notification.body.group.title", map[string]any{"SenderName": senderName})
|
||||
data.Props["SubTitle"] = translateFunc("app.notification.body.group.subTitle", map[string]any{"SenderName": senderName})
|
||||
if emailNotification.IsDirectMessage || emailNotification.IsGroupMessage {
|
||||
// No channel name for DM/GM
|
||||
} else {
|
||||
// mentions
|
||||
data.Props["Title"] = translateFunc("app.notification.body.mention.title", map[string]any{"SenderName": senderName})
|
||||
data.Props["SubTitle"] = translateFunc("app.notification.body.mention.subTitle", map[string]any{"SenderName": senderName, "ChannelName": channelName})
|
||||
pData.ChannelName = channelName
|
||||
pData.ChannelName = emailNotification.ChannelName
|
||||
}
|
||||
|
||||
// Override title and subtile for replies with CRT enabled
|
||||
if a.IsCRTEnabledForUser(c, recipient.Id) && post.RootId != "" {
|
||||
// Title is the same in all cases
|
||||
data.Props["Title"] = translateFunc("app.notification.body.thread.title", map[string]any{"SenderName": senderName})
|
||||
|
||||
if channel.Type == model.ChannelTypeDirect {
|
||||
// Direct Reply
|
||||
data.Props["SubTitle"] = translateFunc("app.notification.body.thread_dm.subTitle", map[string]any{"SenderName": senderName})
|
||||
} else if channel.Type == model.ChannelTypeGroup {
|
||||
// Group Reply
|
||||
data.Props["SubTitle"] = translateFunc("app.notification.body.thread_gm.subTitle", map[string]any{"SenderName": senderName})
|
||||
} else if emailNotificationContentsType == model.EmailNotificationContentsFull {
|
||||
// Channel Reply with full content
|
||||
data.Props["SubTitle"] = translateFunc("app.notification.body.thread_channel_full.subTitle", map[string]any{"SenderName": senderName, "ChannelName": channelName})
|
||||
} else {
|
||||
// Channel Reply with generic content
|
||||
data.Props["SubTitle"] = translateFunc("app.notification.body.thread_channel.subTitle", map[string]any{"SenderName": senderName})
|
||||
}
|
||||
}
|
||||
|
||||
// only include posts in notification email if email notification contents type is set to full
|
||||
if emailNotificationContentsType == model.EmailNotificationContentsFull {
|
||||
// Only include posts in notification email if message content is available
|
||||
if emailNotification.MessageHTML != "" {
|
||||
data.Props["Posts"] = []postData{pData}
|
||||
} else {
|
||||
data.Props["Posts"] = []postData{}
|
||||
|
|
@ -295,7 +394,3 @@ func (a *App) getNotificationEmailBody(c request.CTX, recipient *model.User, pos
|
|||
|
||||
return a.Srv().TemplatesContainer().RenderToString("messages_notification", data)
|
||||
}
|
||||
|
||||
func (a *App) GetMessageForNotification(post *model.Post, teamName, siteUrl string, translateFunc i18n.TranslateFunc) string {
|
||||
return a.Srv().EmailService.GetMessageForNotification(post, teamName, siteUrl, translateFunc)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,9 +18,52 @@ import (
|
|||
"github.com/mattermost/mattermost/server/public/shared/i18n"
|
||||
"github.com/mattermost/mattermost/server/public/shared/timezones"
|
||||
"github.com/mattermost/mattermost/server/v8/channels/store/storetest/mocks"
|
||||
"github.com/mattermost/mattermost/server/v8/channels/testlib"
|
||||
"github.com/mattermost/mattermost/server/v8/channels/utils"
|
||||
)
|
||||
|
||||
// Helper function to create PostNotification for testing
|
||||
func buildTestPostNotification(post *model.Post, channel *model.Channel, sender *model.User) *PostNotification {
|
||||
return &PostNotification{
|
||||
Channel: channel,
|
||||
Post: post,
|
||||
Sender: sender,
|
||||
ProfileMap: make(map[string]*model.User),
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to create test user
|
||||
func buildTestUser(id, username, displayName string, useMilitaryTime bool) *model.User {
|
||||
return &model.User{
|
||||
Id: id,
|
||||
Username: username,
|
||||
Nickname: displayName,
|
||||
Locale: "en",
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to create test team
|
||||
func buildTestTeam(id, name, displayName string) *model.Team {
|
||||
return &model.Team{
|
||||
Id: id,
|
||||
Name: name,
|
||||
DisplayName: displayName,
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to set up preference mocks
|
||||
func setupPreferenceMocks(th *TestHelper, userId string, useMilitaryTime bool) {
|
||||
preferenceStoreMock := mocks.PreferenceStore{}
|
||||
if useMilitaryTime {
|
||||
preferenceStoreMock.On("Get", userId, model.PreferenceCategoryDisplaySettings, model.PreferenceNameUseMilitaryTime).Return(&model.Preference{Value: "true"}, nil)
|
||||
} else {
|
||||
preferenceStoreMock.On("Get", userId, model.PreferenceCategoryDisplaySettings, model.PreferenceNameUseMilitaryTime).Return(&model.Preference{Value: "false"}, nil)
|
||||
}
|
||||
// Mock the name format preference as well
|
||||
preferenceStoreMock.On("Get", userId, model.PreferenceCategoryDisplaySettings, model.PreferenceNameNameFormat).Return(&model.Preference{Value: model.ShowUsername}, nil)
|
||||
th.App.Srv().Store().(*mocks.Store).On("Preference").Return(&preferenceStoreMock)
|
||||
}
|
||||
|
||||
func TestGetDirectMessageNotificationEmailSubject(t *testing.T) {
|
||||
mainHelper.Parallel(t)
|
||||
expectedPrefix := "[http://localhost:8065] New Direct Message from @sender on"
|
||||
|
|
@ -76,31 +119,34 @@ func TestGetNotificationEmailBodyFullNotificationPublicChannel(t *testing.T) {
|
|||
th := SetupWithStoreMock(t)
|
||||
defer th.TearDown()
|
||||
|
||||
recipient := &model.User{}
|
||||
recipient := buildTestUser("test-recipient-id", "recipient", "Recipient User", true)
|
||||
post := &model.Post{
|
||||
Id: "test-post-id",
|
||||
Message: "This is the message",
|
||||
}
|
||||
channel := &model.Channel{
|
||||
Id: "test-channel-id",
|
||||
Name: "testchannel",
|
||||
DisplayName: "ChannelName",
|
||||
Type: model.ChannelTypeOpen,
|
||||
}
|
||||
channelName := "ChannelName"
|
||||
senderName := "sender"
|
||||
teamName := "testteam"
|
||||
teamURL := "http://localhost:8065/testteam"
|
||||
emailNotificationContentsType := model.EmailNotificationContentsFull
|
||||
translateFunc := i18n.GetUserTranslations("en")
|
||||
sender := buildTestUser("test-sender-id", "sender", "sender", true)
|
||||
team := buildTestTeam("test-team-id", "testteam", "testteam")
|
||||
|
||||
storeMock := th.App.Srv().Store().(*mocks.Store)
|
||||
teamStoreMock := mocks.TeamStore{}
|
||||
teamStoreMock.On("GetByName", "testteam").Return(&model.Team{Name: "testteam"}, nil)
|
||||
storeMock.On("Team").Return(&teamStoreMock)
|
||||
|
||||
body, err := th.App.getNotificationEmailBody(th.Context, recipient, post, channel, channelName, senderName, teamName, teamURL, emailNotificationContentsType, true, translateFunc, "user-avatar.png")
|
||||
setupPreferenceMocks(th, recipient.Id, true)
|
||||
|
||||
notification := buildTestPostNotification(post, channel, sender)
|
||||
emailNotification := th.App.buildEmailNotification(th.Context, notification, recipient, team)
|
||||
body, err := th.App.getNotificationEmailBodyFromEmailNotification(th.Context, recipient, emailNotification, post, "user-avatar.png")
|
||||
require.NoError(t, err)
|
||||
require.Contains(t, body, "mentioned you in a message", fmt.Sprintf("Expected email text 'mentioned you in a message. Got %s", body))
|
||||
require.Contains(t, body, post.Message, fmt.Sprintf("Expected email text '%s'. Got %s", post.Message, body))
|
||||
require.Contains(t, body, teamURL, fmt.Sprintf("Expected email text '%s'. Got %s", teamURL, body))
|
||||
require.Contains(t, body, team.Name, fmt.Sprintf("Expected email text '%s'. Got %s", team.Name, body))
|
||||
}
|
||||
|
||||
func TestGetNotificationEmailBodyFullNotificationGroupChannel(t *testing.T) {
|
||||
|
|
@ -108,31 +154,34 @@ func TestGetNotificationEmailBodyFullNotificationGroupChannel(t *testing.T) {
|
|||
th := SetupWithStoreMock(t)
|
||||
defer th.TearDown()
|
||||
|
||||
recipient := &model.User{}
|
||||
recipient := buildTestUser("test-recipient-id", "recipient", "Recipient User", true)
|
||||
post := &model.Post{
|
||||
Id: "test-post-id",
|
||||
Message: "This is the message",
|
||||
}
|
||||
channel := &model.Channel{
|
||||
Id: "test-channel-id",
|
||||
Name: "testchannel",
|
||||
DisplayName: "ChannelName",
|
||||
Type: model.ChannelTypeGroup,
|
||||
}
|
||||
channelName := "ChannelName"
|
||||
senderName := "sender"
|
||||
teamName := "testteam"
|
||||
teamURL := "http://localhost:8065/testteam"
|
||||
emailNotificationContentsType := model.EmailNotificationContentsFull
|
||||
translateFunc := i18n.GetUserTranslations("en")
|
||||
sender := buildTestUser("test-sender-id", "sender", "sender", true)
|
||||
team := buildTestTeam("test-team-id", "testteam", "testteam")
|
||||
|
||||
storeMock := th.App.Srv().Store().(*mocks.Store)
|
||||
teamStoreMock := mocks.TeamStore{}
|
||||
teamStoreMock.On("GetByName", "testteam").Return(&model.Team{Name: "testteam"}, nil)
|
||||
storeMock.On("Team").Return(&teamStoreMock)
|
||||
|
||||
body, err := th.App.getNotificationEmailBody(th.Context, recipient, post, channel, channelName, senderName, teamName, teamURL, emailNotificationContentsType, true, translateFunc, "user-avatar.png")
|
||||
setupPreferenceMocks(th, recipient.Id, true)
|
||||
|
||||
notification := buildTestPostNotification(post, channel, sender)
|
||||
emailNotification := th.App.buildEmailNotification(th.Context, notification, recipient, team)
|
||||
body, err := th.App.getNotificationEmailBodyFromEmailNotification(th.Context, recipient, emailNotification, post, "user-avatar.png")
|
||||
require.NoError(t, err)
|
||||
require.Contains(t, body, "sent you a new message", fmt.Sprintf("Expected email text 'sent you a new message. Got %s", body))
|
||||
require.Contains(t, body, post.Message, fmt.Sprintf("Expected email text '%s'. Got %s", post.Message, body))
|
||||
require.Contains(t, body, teamURL, fmt.Sprintf("Expected email text '%s'. Got %s", teamURL, body))
|
||||
require.Contains(t, body, team.Name, fmt.Sprintf("Expected email text '%s'. Got %s", team.Name, body))
|
||||
}
|
||||
|
||||
func TestGetNotificationEmailBodyFullNotificationPrivateChannel(t *testing.T) {
|
||||
|
|
@ -140,31 +189,34 @@ func TestGetNotificationEmailBodyFullNotificationPrivateChannel(t *testing.T) {
|
|||
th := SetupWithStoreMock(t)
|
||||
defer th.TearDown()
|
||||
|
||||
recipient := &model.User{}
|
||||
recipient := buildTestUser("test-recipient-id", "recipient", "Recipient User", true)
|
||||
post := &model.Post{
|
||||
Id: "test-post-id",
|
||||
Message: "This is the message",
|
||||
}
|
||||
channel := &model.Channel{
|
||||
Id: "test-channel-id",
|
||||
Name: "testchannel",
|
||||
DisplayName: "ChannelName",
|
||||
Type: model.ChannelTypePrivate,
|
||||
}
|
||||
channelName := "ChannelName"
|
||||
senderName := "sender"
|
||||
teamName := "testteam"
|
||||
teamURL := "http://localhost:8065/testteam"
|
||||
emailNotificationContentsType := model.EmailNotificationContentsFull
|
||||
translateFunc := i18n.GetUserTranslations("en")
|
||||
sender := buildTestUser("test-sender-id", "sender", "sender", true)
|
||||
team := buildTestTeam("test-team-id", "testteam", "testteam")
|
||||
|
||||
storeMock := th.App.Srv().Store().(*mocks.Store)
|
||||
teamStoreMock := mocks.TeamStore{}
|
||||
teamStoreMock.On("GetByName", "testteam").Return(&model.Team{Name: "testteam"}, nil)
|
||||
storeMock.On("Team").Return(&teamStoreMock)
|
||||
|
||||
body, err := th.App.getNotificationEmailBody(th.Context, recipient, post, channel, channelName, senderName, teamName, teamURL, emailNotificationContentsType, true, translateFunc, "user-avatar.png")
|
||||
setupPreferenceMocks(th, recipient.Id, true)
|
||||
|
||||
notification := buildTestPostNotification(post, channel, sender)
|
||||
emailNotification := th.App.buildEmailNotification(th.Context, notification, recipient, team)
|
||||
body, err := th.App.getNotificationEmailBodyFromEmailNotification(th.Context, recipient, emailNotification, post, "user-avatar.png")
|
||||
require.NoError(t, err)
|
||||
require.Contains(t, body, "mentioned you in a message", fmt.Sprintf("Expected email text 'mentioned you in a message. Got %s", body))
|
||||
require.Contains(t, body, post.Message, fmt.Sprintf("Expected email text '%s'. Got %s", post.Message, body))
|
||||
require.Contains(t, body, teamURL, fmt.Sprintf("Expected email text '%s'. Got %s", teamURL, body))
|
||||
require.Contains(t, body, team.Name, fmt.Sprintf("Expected email text '%s'. Got %s", team.Name, body))
|
||||
}
|
||||
|
||||
func TestGetNotificationEmailBodyFullNotificationDirectChannel(t *testing.T) {
|
||||
|
|
@ -172,31 +224,34 @@ func TestGetNotificationEmailBodyFullNotificationDirectChannel(t *testing.T) {
|
|||
th := SetupWithStoreMock(t)
|
||||
defer th.TearDown()
|
||||
|
||||
recipient := &model.User{}
|
||||
recipient := buildTestUser("test-recipient-id", "recipient", "Recipient User", true)
|
||||
post := &model.Post{
|
||||
Id: "test-post-id",
|
||||
Message: "This is the message",
|
||||
}
|
||||
channel := &model.Channel{
|
||||
Id: "test-channel-id",
|
||||
Name: "testchannel",
|
||||
DisplayName: "ChannelName",
|
||||
Type: model.ChannelTypeDirect,
|
||||
}
|
||||
channelName := "ChannelName"
|
||||
senderName := "sender"
|
||||
teamName := "testteam"
|
||||
teamURL := "http://localhost:8065/testteam"
|
||||
emailNotificationContentsType := model.EmailNotificationContentsFull
|
||||
translateFunc := i18n.GetUserTranslations("en")
|
||||
sender := buildTestUser("test-sender-id", "sender", "sender", true)
|
||||
team := buildTestTeam("test-team-id", "testteam", "testteam")
|
||||
|
||||
storeMock := th.App.Srv().Store().(*mocks.Store)
|
||||
teamStoreMock := mocks.TeamStore{}
|
||||
teamStoreMock.On("GetByName", "testteam").Return(&model.Team{Name: "testteam"}, nil)
|
||||
storeMock.On("Team").Return(&teamStoreMock)
|
||||
|
||||
body, err := th.App.getNotificationEmailBody(th.Context, recipient, post, channel, channelName, senderName, teamName, teamURL, emailNotificationContentsType, true, translateFunc, "user-avatar.png")
|
||||
setupPreferenceMocks(th, recipient.Id, true)
|
||||
|
||||
notification := buildTestPostNotification(post, channel, sender)
|
||||
emailNotification := th.App.buildEmailNotification(th.Context, notification, recipient, team)
|
||||
body, err := th.App.getNotificationEmailBodyFromEmailNotification(th.Context, recipient, emailNotification, post, "user-avatar.png")
|
||||
require.NoError(t, err)
|
||||
require.Contains(t, body, "sent you a new message", fmt.Sprintf("Expected email text 'sent you a new message. Got %s", body))
|
||||
require.Contains(t, body, post.Message, fmt.Sprintf("Expected email text '%s'. Got %s", post.Message, body))
|
||||
require.Contains(t, body, teamURL, fmt.Sprintf("Expected email text '%s'. Got %s", teamURL, body))
|
||||
require.Contains(t, body, team.Name, fmt.Sprintf("Expected email text '%s'. Got %s", team.Name, body))
|
||||
}
|
||||
|
||||
func TestGetNotificationEmailBodyFullNotificationLocaleTimeWithTimezone(t *testing.T) {
|
||||
|
|
@ -205,30 +260,37 @@ func TestGetNotificationEmailBodyFullNotificationLocaleTimeWithTimezone(t *testi
|
|||
defer th.TearDown()
|
||||
|
||||
recipient := &model.User{
|
||||
Id: "test-recipient-id",
|
||||
Username: "recipient",
|
||||
Nickname: "Recipient User",
|
||||
Locale: "en",
|
||||
Timezone: timezones.DefaultUserTimezone(),
|
||||
}
|
||||
recipient.Timezone["automaticTimezone"] = "America/New_York"
|
||||
post := &model.Post{
|
||||
Id: "test-post-id",
|
||||
CreateAt: 1524663790000,
|
||||
Message: "This is the message",
|
||||
}
|
||||
channel := &model.Channel{
|
||||
Id: "test-channel-id",
|
||||
Name: "testchannel",
|
||||
DisplayName: "ChannelName",
|
||||
Type: model.ChannelTypeDirect,
|
||||
}
|
||||
channelName := "ChannelName"
|
||||
senderName := "sender"
|
||||
teamName := "testteam"
|
||||
teamURL := "http://localhost:8065/testteam"
|
||||
emailNotificationContentsType := model.EmailNotificationContentsFull
|
||||
translateFunc := i18n.GetUserTranslations("en")
|
||||
sender := buildTestUser("test-sender-id", "sender", "sender", true)
|
||||
team := buildTestTeam("test-team-id", "testteam", "testteam")
|
||||
|
||||
storeMock := th.App.Srv().Store().(*mocks.Store)
|
||||
teamStoreMock := mocks.TeamStore{}
|
||||
teamStoreMock.On("GetByName", "testteam").Return(&model.Team{Name: "testteam"}, nil)
|
||||
storeMock.On("Team").Return(&teamStoreMock)
|
||||
|
||||
body, err := th.App.getNotificationEmailBody(th.Context, recipient, post, channel, channelName, senderName, teamName, teamURL, emailNotificationContentsType, false, translateFunc, "user-avatar.png")
|
||||
setupPreferenceMocks(th, recipient.Id, false)
|
||||
|
||||
notification := buildTestPostNotification(post, channel, sender)
|
||||
emailNotification := th.App.buildEmailNotification(th.Context, notification, recipient, team)
|
||||
body, err := th.App.getNotificationEmailBodyFromEmailNotification(th.Context, recipient, emailNotification, post, "user-avatar.png")
|
||||
require.NoError(t, err)
|
||||
r, _ := regexp.Compile("E([S|D]+)T")
|
||||
zone := r.FindString(body)
|
||||
|
|
@ -241,28 +303,33 @@ func TestGetNotificationEmailBodyFullNotificationLocaleTimeNoTimezone(t *testing
|
|||
defer th.TearDown()
|
||||
|
||||
recipient := &model.User{
|
||||
Id: "test-recipient-id",
|
||||
Username: "recipient",
|
||||
Nickname: "Recipient User",
|
||||
Locale: "en",
|
||||
Timezone: timezones.DefaultUserTimezone(),
|
||||
}
|
||||
post := &model.Post{
|
||||
Id: "test-post-id",
|
||||
CreateAt: 1524681000000,
|
||||
Message: "This is the message",
|
||||
}
|
||||
channel := &model.Channel{
|
||||
Id: "test-channel-id",
|
||||
Name: "testchannel",
|
||||
DisplayName: "ChannelName",
|
||||
Type: model.ChannelTypeDirect,
|
||||
}
|
||||
channelName := "ChannelName"
|
||||
senderName := "sender"
|
||||
teamName := "testteam"
|
||||
teamURL := "http://localhost:8065/testteam"
|
||||
emailNotificationContentsType := model.EmailNotificationContentsFull
|
||||
translateFunc := i18n.GetUserTranslations("en")
|
||||
sender := buildTestUser("test-sender-id", "sender", "sender", true)
|
||||
team := buildTestTeam("test-team-id", "testteam", "testteam")
|
||||
|
||||
storeMock := th.App.Srv().Store().(*mocks.Store)
|
||||
teamStoreMock := mocks.TeamStore{}
|
||||
teamStoreMock.On("GetByName", "testteam").Return(&model.Team{Name: "testteam"}, nil)
|
||||
storeMock.On("Team").Return(&teamStoreMock)
|
||||
|
||||
setupPreferenceMocks(th, recipient.Id, true)
|
||||
|
||||
tm := time.Unix(post.CreateAt/1000, 0)
|
||||
zone, _ := tm.Zone()
|
||||
|
||||
|
|
@ -278,7 +345,9 @@ func TestGetNotificationEmailBodyFullNotificationLocaleTimeNoTimezone(t *testing
|
|||
err = tmp.Execute(&text, fmt.Sprintf("%s:%s %s", formattedTime.Hour, formattedTime.Minute, formattedTime.TimeZone))
|
||||
require.NoError(t, err)
|
||||
|
||||
body, err := th.App.getNotificationEmailBody(th.Context, recipient, post, channel, channelName, senderName, teamName, teamURL, emailNotificationContentsType, true, translateFunc, "user-avatar.png")
|
||||
notification := buildTestPostNotification(post, channel, sender)
|
||||
emailNotification := th.App.buildEmailNotification(th.Context, notification, recipient, team)
|
||||
body, err := th.App.getNotificationEmailBodyFromEmailNotification(th.Context, recipient, emailNotification, post, "user-avatar.png")
|
||||
require.NoError(t, err)
|
||||
postTimeLine := text.String()
|
||||
require.Contains(t, body, postTimeLine, fmt.Sprintf("Expected email text '%s'. Got %s", postTimeLine, body))
|
||||
|
|
@ -290,30 +359,37 @@ func TestGetNotificationEmailBodyFullNotificationLocaleTime12Hour(t *testing.T)
|
|||
defer th.TearDown()
|
||||
|
||||
recipient := &model.User{
|
||||
Id: "test-recipient-id",
|
||||
Username: "recipient",
|
||||
Nickname: "Recipient User",
|
||||
Locale: "en",
|
||||
Timezone: timezones.DefaultUserTimezone(),
|
||||
}
|
||||
recipient.Timezone["automaticTimezone"] = "America/New_York"
|
||||
post := &model.Post{
|
||||
Id: "test-post-id",
|
||||
CreateAt: 1524681000000, // 1524681000 // 1524681000000
|
||||
Message: "This is the message",
|
||||
}
|
||||
channel := &model.Channel{
|
||||
Id: "test-channel-id",
|
||||
Name: "testchannel",
|
||||
DisplayName: "ChannelName",
|
||||
Type: model.ChannelTypeDirect,
|
||||
}
|
||||
channelName := "ChannelName"
|
||||
senderName := "sender"
|
||||
teamName := "testteam"
|
||||
teamURL := "http://localhost:8065/testteam"
|
||||
emailNotificationContentsType := model.EmailNotificationContentsFull
|
||||
translateFunc := i18n.GetUserTranslations("en")
|
||||
sender := buildTestUser("test-sender-id", "sender", "sender", true)
|
||||
team := buildTestTeam("test-team-id", "testteam", "testteam")
|
||||
|
||||
storeMock := th.App.Srv().Store().(*mocks.Store)
|
||||
teamStoreMock := mocks.TeamStore{}
|
||||
teamStoreMock.On("GetByName", "testteam").Return(&model.Team{Name: "testteam"}, nil)
|
||||
storeMock.On("Team").Return(&teamStoreMock)
|
||||
|
||||
body, err := th.App.getNotificationEmailBody(th.Context, recipient, post, channel, channelName, senderName, teamName, teamURL, emailNotificationContentsType, false, translateFunc, "user-avatar.png")
|
||||
setupPreferenceMocks(th, recipient.Id, false)
|
||||
|
||||
notification := buildTestPostNotification(post, channel, sender)
|
||||
emailNotification := th.App.buildEmailNotification(th.Context, notification, recipient, team)
|
||||
body, err := th.App.getNotificationEmailBodyFromEmailNotification(th.Context, recipient, emailNotification, post, "user-avatar.png")
|
||||
require.NoError(t, err)
|
||||
require.Contains(t, body, "2:30 PM", fmt.Sprintf("Expected email text '2:30 PM'. Got %s", body))
|
||||
}
|
||||
|
|
@ -324,30 +400,37 @@ func TestGetNotificationEmailBodyFullNotificationLocaleTime24Hour(t *testing.T)
|
|||
defer th.TearDown()
|
||||
|
||||
recipient := &model.User{
|
||||
Id: "test-recipient-id",
|
||||
Username: "recipient",
|
||||
Nickname: "Recipient User",
|
||||
Locale: "en",
|
||||
Timezone: timezones.DefaultUserTimezone(),
|
||||
}
|
||||
recipient.Timezone["automaticTimezone"] = "America/New_York"
|
||||
post := &model.Post{
|
||||
Id: "test-post-id",
|
||||
CreateAt: 1524681000000,
|
||||
Message: "This is the message",
|
||||
}
|
||||
channel := &model.Channel{
|
||||
Id: "test-channel-id",
|
||||
Name: "testchannel",
|
||||
DisplayName: "ChannelName",
|
||||
Type: model.ChannelTypeDirect,
|
||||
}
|
||||
channelName := "ChannelName"
|
||||
senderName := "sender"
|
||||
teamName := "testteam"
|
||||
teamURL := "http://localhost:8065/testteam"
|
||||
emailNotificationContentsType := model.EmailNotificationContentsFull
|
||||
translateFunc := i18n.GetUserTranslations("en")
|
||||
sender := buildTestUser("test-sender-id", "sender", "sender", true)
|
||||
team := buildTestTeam("test-team-id", "testteam", "testteam")
|
||||
|
||||
storeMock := th.App.Srv().Store().(*mocks.Store)
|
||||
teamStoreMock := mocks.TeamStore{}
|
||||
teamStoreMock.On("GetByName", "testteam").Return(&model.Team{Name: "testteam"}, nil)
|
||||
storeMock.On("Team").Return(&teamStoreMock)
|
||||
|
||||
body, err := th.App.getNotificationEmailBody(th.Context, recipient, post, channel, channelName, senderName, teamName, teamURL, emailNotificationContentsType, true, translateFunc, "user-avatar.png")
|
||||
setupPreferenceMocks(th, recipient.Id, true)
|
||||
|
||||
notification := buildTestPostNotification(post, channel, sender)
|
||||
emailNotification := th.App.buildEmailNotification(th.Context, notification, recipient, team)
|
||||
body, err := th.App.getNotificationEmailBodyFromEmailNotification(th.Context, recipient, emailNotification, post, "user-avatar.png")
|
||||
require.NoError(t, err)
|
||||
require.Contains(t, body, "14:30", fmt.Sprintf("Expected email text '14:30'. Got %s", body))
|
||||
}
|
||||
|
|
@ -358,26 +441,29 @@ func TestGetNotificationEmailBodyWithUserPreference(t *testing.T) {
|
|||
defer th.TearDown()
|
||||
|
||||
recipient := &model.User{
|
||||
Id: "test-recipient-id",
|
||||
Username: "recipient",
|
||||
Nickname: "Recipient User",
|
||||
Locale: "en",
|
||||
Timezone: timezones.DefaultUserTimezone(),
|
||||
}
|
||||
recipient.Timezone["automaticTimezone"] = "America/New_York"
|
||||
|
||||
post := &model.Post{
|
||||
Id: "test-post-id",
|
||||
CreateAt: 1524681000000,
|
||||
Message: "This is the message",
|
||||
}
|
||||
|
||||
channel := &model.Channel{
|
||||
Id: "test-channel-id",
|
||||
Name: "testchannel",
|
||||
DisplayName: "ChannelName",
|
||||
Type: model.ChannelTypeDirect,
|
||||
}
|
||||
|
||||
channelName := "ChannelName"
|
||||
senderName := "sender"
|
||||
teamName := "testteam"
|
||||
teamURL := "http://localhost:8065/testteam"
|
||||
emailNotificationContentsType := model.EmailNotificationContentsFull
|
||||
translateFunc := i18n.GetUserTranslations("en")
|
||||
sender := buildTestUser("test-sender-id", "sender", "sender", true)
|
||||
team := buildTestTeam("test-team-id", "testteam", "testteam")
|
||||
|
||||
storeMock := th.App.Srv().Store().(*mocks.Store)
|
||||
teamStoreMock := mocks.TeamStore{}
|
||||
|
|
@ -392,7 +478,11 @@ func TestGetNotificationEmailBodyWithUserPreference(t *testing.T) {
|
|||
expectedTimeFormat = "14:30"
|
||||
}
|
||||
|
||||
body, err := th.App.getNotificationEmailBody(th.Context, recipient, post, channel, channelName, senderName, teamName, teamURL, emailNotificationContentsType, is24HourFormat, translateFunc, "user-avatar.png")
|
||||
setupPreferenceMocks(th, recipient.Id, is24HourFormat)
|
||||
|
||||
notification := buildTestPostNotification(post, channel, sender)
|
||||
emailNotification := th.App.buildEmailNotification(th.Context, notification, recipient, team)
|
||||
body, err := th.App.getNotificationEmailBodyFromEmailNotification(th.Context, recipient, emailNotification, post, "user-avatar.png")
|
||||
require.NoError(t, err)
|
||||
require.Contains(t, body, expectedTimeFormat, fmt.Sprintf("Expected email text '%s'. Got %s", expectedTimeFormat, body))
|
||||
}
|
||||
|
|
@ -402,8 +492,9 @@ func TestGetNotificationEmailBodyFullNotificationWithSlackAttachments(t *testing
|
|||
th := SetupWithStoreMock(t)
|
||||
defer th.TearDown()
|
||||
|
||||
recipient := &model.User{}
|
||||
recipient := buildTestUser("test-recipient-id", "recipient", "Recipient User", true)
|
||||
post := &model.Post{
|
||||
Id: "test-post-id",
|
||||
Message: "This is the message",
|
||||
}
|
||||
|
||||
|
|
@ -453,23 +544,25 @@ func TestGetNotificationEmailBodyFullNotificationWithSlackAttachments(t *testing
|
|||
model.ParseSlackAttachment(post, messageAttachments)
|
||||
|
||||
channel := &model.Channel{
|
||||
Id: "test-channel-id",
|
||||
Name: "testchannel",
|
||||
DisplayName: "ChannelName",
|
||||
Type: model.ChannelTypeOpen,
|
||||
}
|
||||
|
||||
channelName := "ChannelName"
|
||||
senderName := "sender"
|
||||
teamName := "testteam"
|
||||
teamURL := "http://localhost:8065/testteam"
|
||||
emailNotificationContentsType := model.EmailNotificationContentsFull
|
||||
translateFunc := i18n.GetUserTranslations("en")
|
||||
sender := buildTestUser("test-sender-id", "sender", "sender", true)
|
||||
team := buildTestTeam("test-team-id", "testteam", "testteam")
|
||||
|
||||
storeMock := th.App.Srv().Store().(*mocks.Store)
|
||||
teamStoreMock := mocks.TeamStore{}
|
||||
teamStoreMock.On("GetByName", "testteam").Return(&model.Team{Name: "testteam"}, nil)
|
||||
storeMock.On("Team").Return(&teamStoreMock)
|
||||
|
||||
body, err := th.App.getNotificationEmailBody(th.Context, recipient, post, channel, channelName, senderName, teamName, teamURL, emailNotificationContentsType, true, translateFunc, "user-avatar.png")
|
||||
setupPreferenceMocks(th, recipient.Id, true)
|
||||
|
||||
notification := buildTestPostNotification(post, channel, sender)
|
||||
emailNotification := th.App.buildEmailNotification(th.Context, notification, recipient, team)
|
||||
body, err := th.App.getNotificationEmailBodyFromEmailNotification(th.Context, recipient, emailNotification, post, "user-avatar.png")
|
||||
require.NoError(t, err)
|
||||
require.Contains(t, body, "#FF0000")
|
||||
require.Contains(t, body, "message attachment 1 pretext")
|
||||
|
|
@ -501,30 +594,33 @@ func TestGetNotificationEmailBodyGenericNotificationPublicChannel(t *testing.T)
|
|||
th := SetupWithStoreMock(t)
|
||||
defer th.TearDown()
|
||||
|
||||
recipient := &model.User{}
|
||||
recipient := buildTestUser("test-recipient-id", "recipient", "Recipient User", true)
|
||||
post := &model.Post{
|
||||
Id: "test-post-id",
|
||||
Message: "This is the message",
|
||||
}
|
||||
channel := &model.Channel{
|
||||
Id: "test-channel-id",
|
||||
Name: "testchannel",
|
||||
DisplayName: "ChannelName",
|
||||
Type: model.ChannelTypeOpen,
|
||||
}
|
||||
channelName := "ChannelName"
|
||||
senderName := "sender"
|
||||
teamName := "testteam"
|
||||
teamURL := "http://localhost:8065/testteam"
|
||||
emailNotificationContentsType := model.EmailNotificationContentsGeneric
|
||||
translateFunc := i18n.GetUserTranslations("en")
|
||||
sender := buildTestUser("test-sender-id", "sender", "sender", true)
|
||||
team := buildTestTeam("test-team-id", "testteam", "testteam")
|
||||
|
||||
storeMock := th.App.Srv().Store().(*mocks.Store)
|
||||
teamStoreMock := mocks.TeamStore{}
|
||||
teamStoreMock.On("GetByName", "testteam").Return(&model.Team{Name: "testteam"}, nil)
|
||||
storeMock.On("Team").Return(&teamStoreMock)
|
||||
|
||||
body, err := th.App.getNotificationEmailBody(th.Context, recipient, post, channel, channelName, senderName, teamName, teamURL, emailNotificationContentsType, true, translateFunc, "user-avatar.png")
|
||||
setupPreferenceMocks(th, recipient.Id, true)
|
||||
|
||||
notification := buildTestPostNotification(post, channel, sender)
|
||||
emailNotification := th.App.buildEmailNotification(th.Context, notification, recipient, team)
|
||||
body, err := th.App.getNotificationEmailBodyFromEmailNotification(th.Context, recipient, emailNotification, post, "user-avatar.png")
|
||||
require.NoError(t, err)
|
||||
require.Contains(t, body, "mentioned you in a message", fmt.Sprintf("Expected email text 'mentioned you in a message. Got %s", body))
|
||||
require.Contains(t, body, teamURL, fmt.Sprintf("Expected email text '%s'. Got %s", teamURL, body))
|
||||
require.Contains(t, body, team.Name, fmt.Sprintf("Expected email text '%s'. Got %s", team.Name, body))
|
||||
}
|
||||
|
||||
func TestGetNotificationEmailBodyGenericNotificationGroupChannel(t *testing.T) {
|
||||
|
|
@ -532,30 +628,33 @@ func TestGetNotificationEmailBodyGenericNotificationGroupChannel(t *testing.T) {
|
|||
th := SetupWithStoreMock(t)
|
||||
defer th.TearDown()
|
||||
|
||||
recipient := &model.User{}
|
||||
recipient := buildTestUser("test-recipient-id", "recipient", "Recipient User", true)
|
||||
post := &model.Post{
|
||||
Id: "test-post-id",
|
||||
Message: "This is the message",
|
||||
}
|
||||
channel := &model.Channel{
|
||||
Id: "test-channel-id",
|
||||
Name: "testchannel",
|
||||
DisplayName: "ChannelName",
|
||||
Type: model.ChannelTypeGroup,
|
||||
}
|
||||
channelName := "ChannelName"
|
||||
senderName := "sender"
|
||||
teamName := "testteam"
|
||||
teamURL := "http://localhost:8065/testteam"
|
||||
emailNotificationContentsType := model.EmailNotificationContentsGeneric
|
||||
translateFunc := i18n.GetUserTranslations("en")
|
||||
sender := buildTestUser("test-sender-id", "sender", "sender", true)
|
||||
team := buildTestTeam("test-team-id", "testteam", "testteam")
|
||||
|
||||
storeMock := th.App.Srv().Store().(*mocks.Store)
|
||||
teamStoreMock := mocks.TeamStore{}
|
||||
teamStoreMock.On("GetByName", "testteam").Return(&model.Team{Name: "testteam"}, nil)
|
||||
storeMock.On("Team").Return(&teamStoreMock)
|
||||
|
||||
body, err := th.App.getNotificationEmailBody(th.Context, recipient, post, channel, channelName, senderName, teamName, teamURL, emailNotificationContentsType, true, translateFunc, "user-avatar.png")
|
||||
setupPreferenceMocks(th, recipient.Id, true)
|
||||
|
||||
notification := buildTestPostNotification(post, channel, sender)
|
||||
emailNotification := th.App.buildEmailNotification(th.Context, notification, recipient, team)
|
||||
body, err := th.App.getNotificationEmailBodyFromEmailNotification(th.Context, recipient, emailNotification, post, "user-avatar.png")
|
||||
require.NoError(t, err)
|
||||
require.Contains(t, body, "sent you a new message", fmt.Sprintf("Expected email text 'sent you a new message. Got %s", body))
|
||||
require.Contains(t, body, teamURL, fmt.Sprintf("Expected email text '%s'. Got %s", teamURL, body))
|
||||
require.Contains(t, body, team.Name, fmt.Sprintf("Expected email text '%s'. Got %s", team.Name, body))
|
||||
}
|
||||
|
||||
func TestGetNotificationEmailBodyGenericNotificationPrivateChannel(t *testing.T) {
|
||||
|
|
@ -563,30 +662,33 @@ func TestGetNotificationEmailBodyGenericNotificationPrivateChannel(t *testing.T)
|
|||
th := SetupWithStoreMock(t)
|
||||
defer th.TearDown()
|
||||
|
||||
recipient := &model.User{}
|
||||
recipient := buildTestUser("test-recipient-id", "recipient", "Recipient User", true)
|
||||
post := &model.Post{
|
||||
Id: "test-post-id",
|
||||
Message: "This is the message",
|
||||
}
|
||||
channel := &model.Channel{
|
||||
Id: "test-channel-id",
|
||||
Name: "testchannel",
|
||||
DisplayName: "ChannelName",
|
||||
Type: model.ChannelTypePrivate,
|
||||
}
|
||||
channelName := "ChannelName"
|
||||
senderName := "sender"
|
||||
teamName := "testteam"
|
||||
teamURL := "http://localhost:8065/testteam"
|
||||
emailNotificationContentsType := model.EmailNotificationContentsGeneric
|
||||
translateFunc := i18n.GetUserTranslations("en")
|
||||
sender := buildTestUser("test-sender-id", "sender", "sender", true)
|
||||
team := buildTestTeam("test-team-id", "testteam", "testteam")
|
||||
|
||||
storeMock := th.App.Srv().Store().(*mocks.Store)
|
||||
teamStoreMock := mocks.TeamStore{}
|
||||
teamStoreMock.On("GetByName", "testteam").Return(&model.Team{Name: "testteam"}, nil)
|
||||
storeMock.On("Team").Return(&teamStoreMock)
|
||||
|
||||
body, err := th.App.getNotificationEmailBody(th.Context, recipient, post, channel, channelName, senderName, teamName, teamURL, emailNotificationContentsType, true, translateFunc, "user-avatar.png")
|
||||
setupPreferenceMocks(th, recipient.Id, true)
|
||||
|
||||
notification := buildTestPostNotification(post, channel, sender)
|
||||
emailNotification := th.App.buildEmailNotification(th.Context, notification, recipient, team)
|
||||
body, err := th.App.getNotificationEmailBodyFromEmailNotification(th.Context, recipient, emailNotification, post, "user-avatar.png")
|
||||
require.NoError(t, err)
|
||||
require.Contains(t, body, "mentioned you in a message", fmt.Sprintf("Expected email text 'mentioned you in a message. Got %s", body))
|
||||
require.Contains(t, body, teamURL, fmt.Sprintf("Expected email text '%s'. Got %s", teamURL, body))
|
||||
require.Contains(t, body, team.Name, fmt.Sprintf("Expected email text '%s'. Got %s", team.Name, body))
|
||||
}
|
||||
|
||||
func TestGetNotificationEmailBodyGenericNotificationDirectChannel(t *testing.T) {
|
||||
|
|
@ -594,30 +696,33 @@ func TestGetNotificationEmailBodyGenericNotificationDirectChannel(t *testing.T)
|
|||
th := SetupWithStoreMock(t)
|
||||
defer th.TearDown()
|
||||
|
||||
recipient := &model.User{}
|
||||
recipient := buildTestUser("test-recipient-id", "recipient", "Recipient User", true)
|
||||
post := &model.Post{
|
||||
Id: "test-post-id",
|
||||
Message: "This is the message",
|
||||
}
|
||||
channel := &model.Channel{
|
||||
Id: "test-channel-id",
|
||||
Name: "testchannel",
|
||||
DisplayName: "ChannelName",
|
||||
Type: model.ChannelTypeDirect,
|
||||
}
|
||||
channelName := "ChannelName"
|
||||
senderName := "sender"
|
||||
teamName := "testteam"
|
||||
teamURL := "http://localhost:8065/testteam"
|
||||
emailNotificationContentsType := model.EmailNotificationContentsGeneric
|
||||
translateFunc := i18n.GetUserTranslations("en")
|
||||
sender := buildTestUser("test-sender-id", "sender", "sender", true)
|
||||
team := buildTestTeam("test-team-id", "testteam", "testteam")
|
||||
|
||||
storeMock := th.App.Srv().Store().(*mocks.Store)
|
||||
teamStoreMock := mocks.TeamStore{}
|
||||
teamStoreMock.On("GetByName", "testteam").Return(&model.Team{Name: "testteam"}, nil)
|
||||
storeMock.On("Team").Return(&teamStoreMock)
|
||||
|
||||
body, err := th.App.getNotificationEmailBody(th.Context, recipient, post, channel, channelName, senderName, teamName, teamURL, emailNotificationContentsType, true, translateFunc, "user-avatar.png")
|
||||
setupPreferenceMocks(th, recipient.Id, true)
|
||||
|
||||
notification := buildTestPostNotification(post, channel, sender)
|
||||
emailNotification := th.App.buildEmailNotification(th.Context, notification, recipient, team)
|
||||
body, err := th.App.getNotificationEmailBodyFromEmailNotification(th.Context, recipient, emailNotification, post, "user-avatar.png")
|
||||
require.NoError(t, err)
|
||||
require.Contains(t, body, "sent you a new message", fmt.Sprintf("Expected email text 'sent you a new message. Got %s", body))
|
||||
require.Contains(t, body, teamURL, fmt.Sprintf("Expected email text '%s'. Got %s", teamURL, body))
|
||||
require.Contains(t, body, team.Name, fmt.Sprintf("Expected email text '%s'. Got %s", team.Name, body))
|
||||
}
|
||||
|
||||
func TestGetNotificationEmailEscapingChars(t *testing.T) {
|
||||
|
|
@ -625,31 +730,32 @@ func TestGetNotificationEmailEscapingChars(t *testing.T) {
|
|||
th := SetupWithStoreMock(t)
|
||||
defer th.TearDown()
|
||||
|
||||
ch := &model.Channel{
|
||||
DisplayName: "ChannelName",
|
||||
Type: model.ChannelTypeOpen,
|
||||
}
|
||||
channelName := "ChannelName"
|
||||
recipient := &model.User{}
|
||||
recipient := buildTestUser("test-recipient-id", "recipient", "Recipient User", true)
|
||||
message := "<b>Bold Test</b>"
|
||||
post := &model.Post{
|
||||
Id: "test-post-id",
|
||||
Message: message,
|
||||
}
|
||||
|
||||
senderName := "sender"
|
||||
teamName := "testteam"
|
||||
teamURL := "http://localhost:8065/testteam"
|
||||
emailNotificationContentsType := model.EmailNotificationContentsFull
|
||||
translateFunc := i18n.GetUserTranslations("en")
|
||||
ch := &model.Channel{
|
||||
Id: "test-channel-id",
|
||||
Name: "testchannel",
|
||||
DisplayName: "ChannelName",
|
||||
Type: model.ChannelTypeOpen,
|
||||
}
|
||||
sender := buildTestUser("test-sender-id", "sender", "sender", true)
|
||||
team := buildTestTeam("test-team-id", "testteam", "testteam")
|
||||
|
||||
storeMock := th.App.Srv().Store().(*mocks.Store)
|
||||
teamStoreMock := mocks.TeamStore{}
|
||||
teamStoreMock.On("GetByName", "testteam").Return(&model.Team{Name: "testteam"}, nil)
|
||||
storeMock.On("Team").Return(&teamStoreMock)
|
||||
|
||||
body, err := th.App.getNotificationEmailBody(th.Context, recipient, post, ch,
|
||||
channelName, senderName, teamName, teamURL,
|
||||
emailNotificationContentsType, true, translateFunc, "user-avatar.png")
|
||||
setupPreferenceMocks(th, recipient.Id, true)
|
||||
|
||||
notification := buildTestPostNotification(post, ch, sender)
|
||||
emailNotification := th.App.buildEmailNotification(th.Context, notification, recipient, team)
|
||||
body, err := th.App.getNotificationEmailBodyFromEmailNotification(th.Context, recipient, emailNotification, post, "user-avatar.png")
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.NotContains(t, body, message)
|
||||
|
|
@ -661,27 +767,29 @@ func TestGetNotificationEmailBodyPublicChannelMention(t *testing.T) {
|
|||
defer th.TearDown()
|
||||
|
||||
ch := &model.Channel{
|
||||
Id: "test-channel-id",
|
||||
Name: "channelname",
|
||||
DisplayName: "ChannelName",
|
||||
Type: model.ChannelTypeOpen,
|
||||
}
|
||||
id := model.NewId()
|
||||
recipient := &model.User{
|
||||
Id: "test-recipient-id",
|
||||
Email: "success+" + id + "@simulator.amazonses.com",
|
||||
Username: "un_" + id,
|
||||
Nickname: "nn_" + id,
|
||||
Password: "Password1",
|
||||
EmailVerified: true,
|
||||
Locale: "en",
|
||||
}
|
||||
post := &model.Post{
|
||||
Id: "test-post-id",
|
||||
Message: "This is the message ~" + ch.Name,
|
||||
}
|
||||
|
||||
senderName := "user1"
|
||||
teamName := "testteam"
|
||||
sender := buildTestUser("test-sender-id", "user1", "user1", true)
|
||||
team := buildTestTeam("test-team-id", "testteam", "testteam")
|
||||
teamURL := th.App.GetSiteURL() + "/landing#" + "/testteam"
|
||||
emailNotificationContentsType := model.EmailNotificationContentsFull
|
||||
translateFunc := i18n.GetUserTranslations("en")
|
||||
|
||||
storeMock := th.App.Srv().Store().(*mocks.Store)
|
||||
teamStoreMock := mocks.TeamStore{}
|
||||
|
|
@ -692,11 +800,13 @@ func TestGetNotificationEmailBodyPublicChannelMention(t *testing.T) {
|
|||
channelStoreMock.On("GetByNames", "test", []string{ch.Name}, true).Return([]*model.Channel{ch}, nil)
|
||||
storeMock.On("Channel").Return(&channelStoreMock)
|
||||
|
||||
setupPreferenceMocks(th, recipient.Id, true)
|
||||
|
||||
th.App.Srv().EmailService.SetStore(storeMock)
|
||||
|
||||
body, err := th.App.getNotificationEmailBody(th.Context, recipient, post, ch,
|
||||
ch.Name, senderName, teamName, teamURL,
|
||||
emailNotificationContentsType, true, translateFunc, "user-avatar.png")
|
||||
notification := buildTestPostNotification(post, ch, sender)
|
||||
emailNotification := th.App.buildEmailNotification(th.Context, notification, recipient, team)
|
||||
body, err := th.App.getNotificationEmailBodyFromEmailNotification(th.Context, recipient, emailNotification, post, "user-avatar.png")
|
||||
require.NoError(t, err)
|
||||
channelURL := teamURL + "/channels/" + ch.Name
|
||||
mention := "~" + ch.Name
|
||||
|
|
@ -734,23 +844,11 @@ func TestGetNotificationEmailBodyMultiPublicChannelMention(t *testing.T) {
|
|||
|
||||
message := fmt.Sprintf("This is the message Channel1: %s; Channel2: %s;"+
|
||||
" Channel3: %s", mention, mention2, mention3)
|
||||
id := model.NewId()
|
||||
recipient := &model.User{
|
||||
Email: "success+" + id + "@simulator.amazonses.com",
|
||||
Username: "un_" + id,
|
||||
Nickname: "nn_" + id,
|
||||
Password: "Password1",
|
||||
EmailVerified: true,
|
||||
}
|
||||
post := &model.Post{
|
||||
Message: message,
|
||||
}
|
||||
|
||||
senderName := "user1"
|
||||
teamName := "testteam"
|
||||
teamURL := th.App.GetSiteURL() + "/landing#" + "/testteam"
|
||||
emailNotificationContentsType := model.EmailNotificationContentsFull
|
||||
translateFunc := i18n.GetUserTranslations("en")
|
||||
|
||||
storeMock := th.App.Srv().Store().(*mocks.Store)
|
||||
teamStoreMock := mocks.TeamStore{}
|
||||
|
|
@ -763,16 +861,22 @@ func TestGetNotificationEmailBodyMultiPublicChannelMention(t *testing.T) {
|
|||
|
||||
th.App.Srv().EmailService.SetStore(storeMock)
|
||||
|
||||
body, err := th.App.getNotificationEmailBody(th.Context, recipient, post, ch,
|
||||
ch.Name, senderName, teamName, teamURL,
|
||||
emailNotificationContentsType, true, translateFunc, "user-avatar.png")
|
||||
require.NoError(t, err)
|
||||
channelURL := teamURL + "/channels/" + ch.Name
|
||||
channelURL2 := teamURL + "/channels/" + ch2.Name
|
||||
channelURL3 := teamURL + "/channels/" + ch3.Name
|
||||
expMessage := fmt.Sprintf("This is the message Channel1: <a href='%s'>%s</a>;"+
|
||||
" Channel2: <a href='%s'>%s</a>; Channel3: <a href='%s'>%s</a>",
|
||||
channelURL, mention, channelURL2, mention2, channelURL3, mention3)
|
||||
recipient := buildTestUser("test-recipient-id", "recipient", "Recipient User", true)
|
||||
sender := buildTestUser("test-sender-id", "user1", "user1", true)
|
||||
team := buildTestTeam("test-team-id", "testteam", "testteam")
|
||||
|
||||
setupPreferenceMocks(th, recipient.Id, true)
|
||||
|
||||
notification := buildTestPostNotification(post, ch, sender)
|
||||
emailNotification := th.App.buildEmailNotification(th.Context, notification, recipient, team)
|
||||
body, err := th.App.getNotificationEmailBodyFromEmailNotification(th.Context, recipient, emailNotification, post, "user-avatar.png")
|
||||
require.NoError(t, err)
|
||||
assert.Contains(t, body, expMessage)
|
||||
}
|
||||
|
||||
|
|
@ -782,27 +886,29 @@ func TestGetNotificationEmailBodyPrivateChannelMention(t *testing.T) {
|
|||
defer th.TearDown()
|
||||
|
||||
ch := &model.Channel{
|
||||
Id: "test-channel-id",
|
||||
Name: "channelname",
|
||||
DisplayName: "ChannelName",
|
||||
Type: model.ChannelTypePrivate,
|
||||
}
|
||||
id := model.NewId()
|
||||
recipient := &model.User{
|
||||
Id: "test-recipient-id",
|
||||
Email: "success+" + id + "@simulator.amazonses.com",
|
||||
Username: "un_" + id,
|
||||
Nickname: "nn_" + id,
|
||||
Password: "Password1",
|
||||
EmailVerified: true,
|
||||
Locale: "en",
|
||||
}
|
||||
post := &model.Post{
|
||||
Id: "test-post-id",
|
||||
Message: "This is the message ~" + ch.Name,
|
||||
}
|
||||
|
||||
senderName := "user1"
|
||||
teamName := "testteam"
|
||||
sender := buildTestUser("test-sender-id", "user1", "user1", true)
|
||||
team := buildTestTeam("test-team-id", "testteam", "testteam")
|
||||
teamURL := "http://localhost:8065/testteam"
|
||||
emailNotificationContentsType := model.EmailNotificationContentsFull
|
||||
translateFunc := i18n.GetUserTranslations("en")
|
||||
|
||||
storeMock := th.App.Srv().Store().(*mocks.Store)
|
||||
teamStoreMock := mocks.TeamStore{}
|
||||
|
|
@ -813,11 +919,13 @@ func TestGetNotificationEmailBodyPrivateChannelMention(t *testing.T) {
|
|||
channelStoreMock.On("GetByNames", "test", []string{ch.Name}, true).Return([]*model.Channel{ch}, nil)
|
||||
storeMock.On("Channel").Return(&channelStoreMock)
|
||||
|
||||
setupPreferenceMocks(th, recipient.Id, true)
|
||||
|
||||
th.App.Srv().EmailService.SetStore(storeMock)
|
||||
|
||||
body, err := th.App.getNotificationEmailBody(th.Context, recipient, post, ch,
|
||||
ch.Name, senderName, teamName, teamURL,
|
||||
emailNotificationContentsType, true, translateFunc, "user-avatar.png")
|
||||
notification := buildTestPostNotification(post, ch, sender)
|
||||
emailNotification := th.App.buildEmailNotification(th.Context, notification, recipient, team)
|
||||
body, err := th.App.getNotificationEmailBodyFromEmailNotification(th.Context, recipient, emailNotification, post, "user-avatar.png")
|
||||
require.NoError(t, err)
|
||||
channelURL := teamURL + "/channels/" + ch.Name
|
||||
mention := "~" + ch.Name
|
||||
|
|
@ -945,63 +1053,81 @@ func TestGenerateHyperlinkForChannelsPrivate(t *testing.T) {
|
|||
|
||||
func TestLandingLink(t *testing.T) {
|
||||
mainHelper.Parallel(t)
|
||||
th := SetupWithStoreMock(t)
|
||||
|
||||
// Create a minimal helper that sets the site URL
|
||||
mockStore := testlib.GetMockStoreForSetupFunctions()
|
||||
th := setupTestHelper(mockStore, mainHelper.GetSQLStore(), mainHelper.GetSQLSettings(), mainHelper.GetSearchEngine(), false, false,
|
||||
func(cfg *model.Config) {
|
||||
cfg.ServiceSettings.SiteURL = model.NewPointer("http://localhost:8065")
|
||||
}, nil, t)
|
||||
defer th.TearDown()
|
||||
|
||||
recipient := &model.User{}
|
||||
recipient := buildTestUser("test-recipient-id", "recipient", "Recipient User", true)
|
||||
post := &model.Post{
|
||||
Id: "test-post-id",
|
||||
Message: "This is the message",
|
||||
}
|
||||
channel := &model.Channel{
|
||||
Id: "test-channel-id",
|
||||
Name: "testchannel",
|
||||
DisplayName: "ChannelName",
|
||||
Type: model.ChannelTypeOpen,
|
||||
}
|
||||
channelName := "ChannelName"
|
||||
senderName := "sender"
|
||||
teamName := "testteam"
|
||||
sender := buildTestUser("test-sender-id", "sender", "sender", true)
|
||||
team := buildTestTeam("test-team-id", "testteam", "testteam")
|
||||
teamURL := "http://localhost:8065/landing#/testteam"
|
||||
emailNotificationContentsType := model.EmailNotificationContentsFull
|
||||
translateFunc := i18n.GetUserTranslations("en")
|
||||
|
||||
storeMock := th.App.Srv().Store().(*mocks.Store)
|
||||
teamStoreMock := mocks.TeamStore{}
|
||||
teamStoreMock.On("GetByName", "testteam").Return(&model.Team{Name: "testteam"}, nil)
|
||||
storeMock.On("Team").Return(&teamStoreMock)
|
||||
|
||||
body, err := th.App.getNotificationEmailBody(th.Context, recipient, post, channel, channelName, senderName, teamName, teamURL, emailNotificationContentsType, true, translateFunc, "user-avatar.png")
|
||||
setupPreferenceMocks(th, recipient.Id, true)
|
||||
|
||||
notification := buildTestPostNotification(post, channel, sender)
|
||||
emailNotification := th.App.buildEmailNotification(th.Context, notification, recipient, team)
|
||||
body, err := th.App.getNotificationEmailBodyFromEmailNotification(th.Context, recipient, emailNotification, post, "user-avatar.png")
|
||||
require.NoError(t, err)
|
||||
require.Contains(t, body, teamURL, fmt.Sprintf("Expected email text '%s'. Got %s", teamURL, body))
|
||||
}
|
||||
|
||||
func TestLandingLinkPermalink(t *testing.T) {
|
||||
mainHelper.Parallel(t)
|
||||
th := SetupWithStoreMock(t)
|
||||
|
||||
// Create a minimal helper that sets the site URL
|
||||
mockStore := testlib.GetMockStoreForSetupFunctions()
|
||||
th := setupTestHelper(mockStore, mainHelper.GetSQLStore(), mainHelper.GetSQLSettings(), mainHelper.GetSearchEngine(), false, false,
|
||||
func(cfg *model.Config) {
|
||||
cfg.ServiceSettings.SiteURL = model.NewPointer("http://localhost:8065")
|
||||
}, nil, t)
|
||||
defer th.TearDown()
|
||||
|
||||
recipient := &model.User{}
|
||||
recipient := buildTestUser("test-recipient-id", "recipient", "Recipient User", true)
|
||||
post := &model.Post{
|
||||
Id: "Test_id",
|
||||
Message: "This is the message",
|
||||
}
|
||||
channel := &model.Channel{
|
||||
Id: "test-channel-id",
|
||||
Name: "testchannel",
|
||||
DisplayName: "ChannelName",
|
||||
Type: model.ChannelTypeOpen,
|
||||
}
|
||||
channelName := "ChannelName"
|
||||
senderName := "sender"
|
||||
teamName := "testteam"
|
||||
teamURL := "http://localhost:8065/landing#/testteam"
|
||||
emailNotificationContentsType := model.EmailNotificationContentsFull
|
||||
translateFunc := i18n.GetUserTranslations("en")
|
||||
sender := buildTestUser("test-sender-id", "sender", "sender", true)
|
||||
team := buildTestTeam("test-team-id", "testteam", "testteam")
|
||||
|
||||
storeMock := th.App.Srv().Store().(*mocks.Store)
|
||||
teamStoreMock := mocks.TeamStore{}
|
||||
teamStoreMock.On("GetByName", "testteam").Return(&model.Team{Name: "testteam"}, nil)
|
||||
storeMock.On("Team").Return(&teamStoreMock)
|
||||
|
||||
body, err := th.App.getNotificationEmailBody(th.Context, recipient, post, channel, channelName, senderName, teamName, teamURL, emailNotificationContentsType, true, translateFunc, "user-avatar.png")
|
||||
setupPreferenceMocks(th, recipient.Id, true)
|
||||
|
||||
notification := buildTestPostNotification(post, channel, sender)
|
||||
emailNotification := th.App.buildEmailNotification(th.Context, notification, recipient, team)
|
||||
body, err := th.App.getNotificationEmailBodyFromEmailNotification(th.Context, recipient, emailNotification, post, "user-avatar.png")
|
||||
require.NoError(t, err)
|
||||
require.Contains(t, body, teamURL+"/pl/"+post.Id, fmt.Sprintf("Expected email text '%s'. Got %s", teamURL, body))
|
||||
require.Contains(t, body, "/pl/"+post.Id, fmt.Sprintf("Expected email text to contain permalink '/pl/%s'. Got %s", post.Id, body))
|
||||
}
|
||||
|
||||
func TestMarkdownConversion(t *testing.T) {
|
||||
|
|
@ -1091,15 +1217,21 @@ func TestMarkdownConversion(t *testing.T) {
|
|||
th := SetupWithStoreMock(t)
|
||||
defer th.TearDown()
|
||||
|
||||
recipient := &model.User{}
|
||||
recipient := buildTestUser("test-recipient-id", "recipient", "Recipient User", true)
|
||||
storeMock := th.App.Srv().Store().(*mocks.Store)
|
||||
teamStoreMock := mocks.TeamStore{}
|
||||
teamStoreMock.On("GetByName", "testteam").Return(&model.Team{Name: "testteam"}, nil)
|
||||
storeMock.On("Team").Return(&teamStoreMock)
|
||||
channel := &model.Channel{
|
||||
Id: "test-channel-id",
|
||||
Name: "testchannel",
|
||||
DisplayName: "ChannelName",
|
||||
Type: model.ChannelTypeOpen,
|
||||
}
|
||||
sender := buildTestUser("test-sender-id", "sender", "sender", true)
|
||||
team := buildTestTeam("test-team-id", "testteam", "testteam")
|
||||
|
||||
setupPreferenceMocks(th, recipient.Id, true)
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
|
@ -1107,7 +1239,9 @@ func TestMarkdownConversion(t *testing.T) {
|
|||
Id: "Test_id",
|
||||
Message: tt.args,
|
||||
}
|
||||
got, err := th.App.getNotificationEmailBody(th.Context, recipient, post, channel, "ChannelName", "sender", "testteam", "http://localhost:8065/landing#/testteam", model.EmailNotificationContentsFull, true, i18n.GetUserTranslations("en"), "user-avatar.png")
|
||||
notification := buildTestPostNotification(post, channel, sender)
|
||||
emailNotification := th.App.buildEmailNotification(th.Context, notification, recipient, team)
|
||||
got, err := th.App.getNotificationEmailBodyFromEmailNotification(th.Context, recipient, emailNotification, post, "user-avatar.png")
|
||||
require.NoError(t, err)
|
||||
require.Contains(t, got, tt.want)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1617,6 +1617,131 @@ func TestHookNotificationWillBePushed(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
//go:embed test_templates/hook_email_notification_will_be_sent.tmpl
|
||||
var hookEmailNotificationWillBeSentTmpl string
|
||||
|
||||
func TestHookEmailNotificationWillBeSent(t *testing.T) {
|
||||
mainHelper.Parallel(t)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
testCode string
|
||||
expectedNotificationSubject string
|
||||
expectedNotificationTitle string
|
||||
expectedButtonText string
|
||||
expectedFooterText string
|
||||
}{
|
||||
{
|
||||
name: "successfully sent",
|
||||
testCode: `return nil, ""`,
|
||||
},
|
||||
{
|
||||
name: "email notification rejected",
|
||||
testCode: `return nil, "rejected"`,
|
||||
},
|
||||
{
|
||||
name: "email notification modified",
|
||||
testCode: `content := &model.EmailNotificationContent{
|
||||
Subject: "Modified Subject by Plugin",
|
||||
Title: "Modified Title by Plugin",
|
||||
ButtonText: "Modified Button by Plugin",
|
||||
FooterText: "Modified Footer by Plugin",
|
||||
}
|
||||
return content, ""`,
|
||||
expectedNotificationSubject: "Modified Subject by Plugin",
|
||||
expectedNotificationTitle: "Modified Title by Plugin",
|
||||
expectedButtonText: "Modified Button by Plugin",
|
||||
expectedFooterText: "Modified Footer by Plugin",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
mainHelper.Parallel(t)
|
||||
|
||||
th := Setup(t).InitBasic()
|
||||
defer th.TearDown()
|
||||
|
||||
// Create a test user for email notifications
|
||||
user := th.CreateUser()
|
||||
th.LinkUserToTeam(user, th.BasicTeam)
|
||||
th.AddUserToChannel(user, th.BasicChannel)
|
||||
|
||||
// Set up email notification preferences to disable batching
|
||||
appErr := th.App.UpdatePreferences(th.Context, user.Id, model.Preferences{
|
||||
{
|
||||
UserId: user.Id,
|
||||
Category: model.PreferenceCategoryNotifications,
|
||||
Name: model.PreferenceNameEmailInterval,
|
||||
Value: model.PreferenceEmailIntervalNoBatchingSeconds,
|
||||
},
|
||||
})
|
||||
require.Nil(t, appErr)
|
||||
|
||||
// Disable email batching in config
|
||||
th.App.UpdateConfig(func(cfg *model.Config) {
|
||||
*cfg.EmailSettings.EnableEmailBatching = false
|
||||
})
|
||||
|
||||
// Create and set up plugin
|
||||
templatedPlugin := fmt.Sprintf(hookEmailNotificationWillBeSentTmpl, tt.testCode)
|
||||
tearDown, _, _ := SetAppEnvironmentWithPlugins(t, []string{templatedPlugin}, th.App, th.NewPluginAPI)
|
||||
defer tearDown()
|
||||
|
||||
// For the modification test, create a simple test that verifies the hook is called
|
||||
// The detailed verification would require more complex mocking which is beyond this test's scope
|
||||
|
||||
// Create a post that will trigger email notification
|
||||
post := &model.Post{
|
||||
UserId: th.BasicUser.Id,
|
||||
ChannelId: th.BasicChannel.Id,
|
||||
Message: "@" + user.Username + " test message",
|
||||
CreateAt: model.GetMillis(),
|
||||
}
|
||||
|
||||
// Create notification
|
||||
notification := &PostNotification{
|
||||
Post: post,
|
||||
Channel: th.BasicChannel,
|
||||
ProfileMap: map[string]*model.User{
|
||||
user.Id: user,
|
||||
},
|
||||
Sender: th.BasicUser,
|
||||
}
|
||||
|
||||
// Send email notification (this will trigger the hook)
|
||||
// Use assert.Eventually to handle any potential race conditions with plugin activation/deactivation
|
||||
assert.Eventually(t, func() bool {
|
||||
modifiedNotification, err := th.App.sendNotificationEmail(th.Context, notification, user, th.BasicTeam, nil)
|
||||
|
||||
// For the rejected test case, we expect the notification to be rejected
|
||||
if tt.name == "email notification rejected" {
|
||||
// When rejected, sendNotificationEmail returns nil for the notification
|
||||
return modifiedNotification == nil && err == nil
|
||||
}
|
||||
if err != nil || modifiedNotification == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// Verify the modified notification fields
|
||||
if tt.expectedNotificationSubject != "" && modifiedNotification.Subject != tt.expectedNotificationSubject {
|
||||
return false
|
||||
}
|
||||
if tt.expectedNotificationTitle != "" && modifiedNotification.Title != tt.expectedNotificationTitle {
|
||||
return false
|
||||
}
|
||||
if tt.expectedButtonText != "" && modifiedNotification.ButtonText != tt.expectedButtonText {
|
||||
return false
|
||||
}
|
||||
if tt.expectedFooterText != "" && modifiedNotification.FooterText != tt.expectedFooterText {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}, 2*time.Second, 100*time.Millisecond)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestHookMessagesWillBeConsumed(t *testing.T) {
|
||||
mainHelper.Parallel(t)
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/mattermost/mattermost/server/public/model"
|
||||
"github.com/mattermost/mattermost/server/public/plugin"
|
||||
)
|
||||
|
||||
type MyPlugin struct {
|
||||
plugin.MattermostPlugin
|
||||
}
|
||||
|
||||
func (p *MyPlugin) EmailNotificationWillBeSent(emailNotification *model.EmailNotification) (*model.EmailNotificationContent, string) {
|
||||
%s
|
||||
}
|
||||
|
||||
func main() {
|
||||
plugin.ClientMain(&MyPlugin{})
|
||||
}
|
||||
37
server/public/model/email_notification.go
Normal file
37
server/public/model/email_notification.go
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
type EmailNotificationContent struct {
|
||||
Subject string `json:"subject,omitempty"`
|
||||
Title string `json:"title,omitempty"`
|
||||
SubTitle string `json:"subtitle,omitempty"`
|
||||
MessageHTML string `json:"message_html,omitempty"`
|
||||
MessageText string `json:"message_text,omitempty"`
|
||||
ButtonText string `json:"button_text,omitempty"`
|
||||
ButtonURL string `json:"button_url,omitempty"`
|
||||
FooterText string `json:"footer_text,omitempty"`
|
||||
}
|
||||
|
||||
type EmailNotification struct {
|
||||
PostId string `json:"post_id"`
|
||||
ChannelId string `json:"channel_id"`
|
||||
TeamId string `json:"team_id"`
|
||||
SenderId string `json:"sender_id"`
|
||||
SenderDisplayName string `json:"sender_display_name,omitempty"`
|
||||
RecipientId string `json:"recipient_id"`
|
||||
RootId string `json:"root_id,omitempty"`
|
||||
|
||||
ChannelType string `json:"channel_type"`
|
||||
ChannelName string `json:"channel_name"`
|
||||
TeamName string `json:"team_name"`
|
||||
SenderUsername string `json:"sender_username"`
|
||||
IsDirectMessage bool `json:"is_direct_message"`
|
||||
IsGroupMessage bool `json:"is_group_message"`
|
||||
IsThreadReply bool `json:"is_thread_reply"`
|
||||
IsCRTEnabled bool `json:"is_crt_enabled"`
|
||||
UseMilitaryTime bool `json:"use_military_time"`
|
||||
|
||||
EmailNotificationContent
|
||||
}
|
||||
|
|
@ -878,6 +878,41 @@ func (s *hooksRPCServer) ConfigurationWillBeSaved(args *Z_ConfigurationWillBeSav
|
|||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
hookNameToId["EmailNotificationWillBeSent"] = EmailNotificationWillBeSentID
|
||||
}
|
||||
|
||||
type Z_EmailNotificationWillBeSentArgs struct {
|
||||
A *model.EmailNotification
|
||||
}
|
||||
|
||||
type Z_EmailNotificationWillBeSentReturns struct {
|
||||
A *model.EmailNotificationContent
|
||||
B string
|
||||
}
|
||||
|
||||
func (g *hooksRPCClient) EmailNotificationWillBeSent(emailNotification *model.EmailNotification) (*model.EmailNotificationContent, string) {
|
||||
_args := &Z_EmailNotificationWillBeSentArgs{emailNotification}
|
||||
_returns := &Z_EmailNotificationWillBeSentReturns{}
|
||||
if g.implemented[EmailNotificationWillBeSentID] {
|
||||
if err := g.client.Call("Plugin.EmailNotificationWillBeSent", _args, _returns); err != nil {
|
||||
g.log.Error("RPC call EmailNotificationWillBeSent to plugin failed.", mlog.Err(err))
|
||||
}
|
||||
}
|
||||
return _returns.A, _returns.B
|
||||
}
|
||||
|
||||
func (s *hooksRPCServer) EmailNotificationWillBeSent(args *Z_EmailNotificationWillBeSentArgs, returns *Z_EmailNotificationWillBeSentReturns) error {
|
||||
if hook, ok := s.impl.(interface {
|
||||
EmailNotificationWillBeSent(emailNotification *model.EmailNotification) (*model.EmailNotificationContent, string)
|
||||
}); ok {
|
||||
returns.A, returns.B = hook.EmailNotificationWillBeSent(args.A)
|
||||
} else {
|
||||
return encodableError(fmt.Errorf("Hook EmailNotificationWillBeSent called but not implemented."))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
hookNameToId["NotificationWillBePushed"] = NotificationWillBePushedID
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ const (
|
|||
OnSharedChannelsProfileImageSyncMsgID = 44
|
||||
GenerateSupportDataID = 45
|
||||
OnSAMLLoginID = 46
|
||||
EmailNotificationWillBeSentID = 47
|
||||
TotalHooksID = iota
|
||||
)
|
||||
|
||||
|
|
@ -314,6 +315,21 @@ type Hooks interface {
|
|||
// Minimum server version: 8.0
|
||||
ConfigurationWillBeSaved(newCfg *model.Config) (*model.Config, error)
|
||||
|
||||
// EmailNotificationWillBeSent is invoked before an email notification is sent to a user.
|
||||
// This allows plugins to customize the email notification content including subject,
|
||||
// title, subtitle, message content, buttons, and other email properties.
|
||||
//
|
||||
// To reject an email notification, return an non-empty string describing why the notification was rejected.
|
||||
// To modify the notification, return the replacement, non-nil *model.EmailNotificationContent and an empty string.
|
||||
// To allow the notification without modification, return a nil *model.EmailNotificationContent and an empty string.
|
||||
//
|
||||
// Note that core identifiers (PostId, ChannelId, TeamId, SenderId, RecipientId, RootId) and
|
||||
// context fields (ChannelType, IsDirectMessage, etc.) are immutable and changes to them will be ignored.
|
||||
// Only customizable content fields can be modified.
|
||||
//
|
||||
// Minimum server version: 11.00
|
||||
EmailNotificationWillBeSent(emailNotification *model.EmailNotification) (*model.EmailNotificationContent, string)
|
||||
|
||||
// NotificationWillBePushed is invoked before a push notification is sent to the push
|
||||
// notification server.
|
||||
//
|
||||
|
|
|
|||
|
|
@ -233,6 +233,13 @@ func (hooks *hooksTimerLayer) ConfigurationWillBeSaved(newCfg *model.Config) (*m
|
|||
return _returnsA, _returnsB
|
||||
}
|
||||
|
||||
func (hooks *hooksTimerLayer) EmailNotificationWillBeSent(emailNotification *model.EmailNotification) (*model.EmailNotificationContent, string) {
|
||||
startTime := timePkg.Now()
|
||||
_returnsA, _returnsB := hooks.hooksImpl.EmailNotificationWillBeSent(emailNotification)
|
||||
hooks.recordTime(startTime, "EmailNotificationWillBeSent", true)
|
||||
return _returnsA, _returnsB
|
||||
}
|
||||
|
||||
func (hooks *hooksTimerLayer) NotificationWillBePushed(pushNotification *model.PushNotification, userID string) (*model.PushNotification, string) {
|
||||
startTime := timePkg.Now()
|
||||
_returnsA, _returnsB := hooks.hooksImpl.NotificationWillBePushed(pushNotification, userID)
|
||||
|
|
|
|||
|
|
@ -57,6 +57,36 @@ func (_m *Hooks) ConfigurationWillBeSaved(newCfg *model.Config) (*model.Config,
|
|||
return r0, r1
|
||||
}
|
||||
|
||||
// EmailNotificationWillBeSent provides a mock function with given fields: emailNotification
|
||||
func (_m *Hooks) EmailNotificationWillBeSent(emailNotification *model.EmailNotification) (*model.EmailNotificationContent, string) {
|
||||
ret := _m.Called(emailNotification)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for EmailNotificationWillBeSent")
|
||||
}
|
||||
|
||||
var r0 *model.EmailNotificationContent
|
||||
var r1 string
|
||||
if rf, ok := ret.Get(0).(func(*model.EmailNotification) (*model.EmailNotificationContent, string)); ok {
|
||||
return rf(emailNotification)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(*model.EmailNotification) *model.EmailNotificationContent); ok {
|
||||
r0 = rf(emailNotification)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*model.EmailNotificationContent)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(*model.EmailNotification) string); ok {
|
||||
r1 = rf(emailNotification)
|
||||
} else {
|
||||
r1 = ret.Get(1).(string)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// ExecuteCommand provides a mock function with given fields: c, args
|
||||
func (_m *Hooks) ExecuteCommand(c *plugin.Context, args *model.CommandArgs) (*model.CommandResponse, *model.AppError) {
|
||||
ret := _m.Called(c, args)
|
||||
|
|
|
|||
Loading…
Reference in a new issue