MM-53924 - Implement push notifications plugin hook and plugin api method (#24350)

* Revert "MM-52804 - Implement SendPushNotification plugin api method (#24273)"

This reverts commit 8418eefb75.

* Revert "MM-53924 - Implement NotificationWillBePushed plugin hook (#24263)"

This reverts commit f13a531bca.

* implement NotificationWillBePushed plugin hook

* implement SendPushNotification plugin api method

* move where we're setting post and channel type

* fix comment

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
Этот коммит содержится в:
Christopher Poile
2023-08-24 12:33:53 -04:00
коммит произвёл GitHub
родитель dad579daee
Коммит 69c11cfe14
16 изменённых файлов: 169 добавлений и 166 удалений

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

@@ -81,6 +81,25 @@ func (a *App) sendPushNotificationSync(c request.CTX, post *model.Post, user *mo
}
func (a *App) sendPushNotificationToAllSessions(msg *model.PushNotification, userID string, skipSessionId string) *model.AppError {
rejectionReason := ""
a.ch.RunMultiHook(func(hooks plugin.Hooks) bool {
var replacementNotification *model.PushNotification
replacementNotification, rejectionReason = hooks.NotificationWillBePushed(msg, userID)
if rejectionReason != "" {
mlog.Info("Notification cancelled by plugin.", mlog.String("rejection reason", rejectionReason))
return false
}
if replacementNotification != nil {
msg = replacementNotification
}
return true
}, plugin.NotificationWillBePushedID)
if rejectionReason != "" {
// Notifications rejected by a plugin should not be considered errors
return nil
}
sessions, err := a.getMobileAppSessions(userID)
if err != nil {
return err
@@ -140,27 +159,6 @@ func (a *App) sendPushNotificationToAllSessions(msg *model.PushNotification, use
}
func (a *App) sendPushNotification(notification *PostNotification, user *model.User, explicitMention, channelWideMention bool, replyToThreadType string) {
cancelled := false
a.ch.RunMultiHook(func(hooks plugin.Hooks) bool {
cancelled = hooks.NotificationWillBePushed(&model.PluginPushNotification{
Post: notification.Post.ForPlugin(),
Channel: notification.Channel,
UserID: user.Id,
ExplicitMention: explicitMention,
ChannelWideMention: channelWideMention,
ReplyToThreadType: replyToThreadType,
})
if cancelled {
mlog.Info("Notification cancelled by plugin")
return false
}
return true
}, plugin.NotificationWillBePushedID)
if cancelled {
return
}
cfg := a.Config()
channel := notification.Channel
post := notification.Post
@@ -606,6 +604,10 @@ func (a *App) BuildPushNotificationMessage(c request.CTX, contentsConfig string,
msg.Badge = badgeCount
// Add post and channel types for plugins to use in the NotificationWillBePushed hook
msg.PostType = post.Type
msg.ChannelType = channel.Type
return msg, nil
}

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

@@ -1468,6 +1468,7 @@ func TestPushNotificationRace(t *testing.T) {
require.NoError(t, err)
s.products["channels"] = ch
app := New(ServerConnector(s.Channels()))
require.NotPanics(t, func() {
s.createPushNotificationsHub(th.Context)
@@ -1475,9 +1476,9 @@ func TestPushNotificationRace(t *testing.T) {
// Now we start sending messages after the PN hub is shut down.
// We test all 3 notification types.
th.App.clearPushNotification("currentSessionId", "userId", "channelId", "")
app.clearPushNotification("currentSessionId", "userId", "channelId", "")
th.App.UpdateMobileAppBadge("userId")
app.UpdateMobileAppBadge("userId")
notification := &PostNotification{
Post: &model.Post{},
@@ -1487,7 +1488,7 @@ func TestPushNotificationRace(t *testing.T) {
},
Sender: &model.User{},
}
th.App.sendPushNotification(notification, &model.User{}, true, false, model.CommentsNotifyAny)
app.sendPushNotification(notification, &model.User{}, true, false, model.CommentsNotifyAny)
})
}

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

@@ -1267,30 +1267,7 @@ func (api *PluginAPI) GetUploadSession(uploadID string) (*model.UploadSession, e
return fi, nil
}
func (api *PluginAPI) SendPluginPushNotification(notification *model.PluginPushNotification) error {
var profiles map[string]*model.User
var err error
if notification.Channel.Type == model.ChannelTypeGroup {
if profiles, err = api.app.Srv().Store().User().GetAllProfilesInChannel(api.ctx.Context(), notification.Channel.Id, true); err != nil {
return err
}
}
sender, appErr := api.app.GetUser(notification.Post.UserId)
if appErr != nil {
return appErr
}
user, appErr := api.app.GetUser(notification.UserID)
if appErr != nil {
return appErr
}
postNotification := &PostNotification{
Post: notification.Post,
Channel: notification.Channel,
ProfileMap: profiles,
Sender: sender,
}
api.app.sendPushNotification(postNotification, user, notification.ExplicitMention, notification.ChannelWideMention, notification.ReplyToThreadType)
return nil
func (api *PluginAPI) SendPushNotification(notification *model.PushNotification, userID string) *model.AppError {
// Ignoring skipSessionId because it's only used internally to clear push notifications
return api.app.sendPushNotificationToAllSessions(notification, userID, "")
}

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

@@ -2266,13 +2266,22 @@ func TestSendPushNotification(t *testing.T) {
defer wg.Done()
post := th.CreatePost(th.BasicChannel)
post.Message = "started a conversation"
notification := &model.PluginPushNotification{
Post: post,
Channel: th.BasicChannel,
UserID: user.Id,
notification := &model.PushNotification{
Category: model.CategoryCanReply,
Version: model.PushMessageV2,
Type: model.PushTypeMessage,
TeamId: th.BasicChannel.TeamId,
ChannelId: th.BasicChannel.Id,
PostId: post.Id,
RootId: post.RootId,
SenderId: post.UserId,
SenderName: "Sender Name",
PostType: post.Type,
ChannelType: th.BasicChannel.Type,
Message: "Custom message",
}
appErr := api.SendPluginPushNotification(notification)
require.NoError(t, appErr)
appErr := api.SendPushNotification(notification, user.Id)
require.Nil(t, appErr)
}(*data.user)
}
wg.Wait()
@@ -2286,7 +2295,7 @@ func TestSendPushNotification(t *testing.T) {
case model.PushTypeMessage:
numMessages++
assert.Equal(t, th.BasicChannel.Id, n.ChannelId)
assert.Equal(t, fmt.Sprintf("@%s: started a conversation", th.BasicUser.GetDisplayName(model.ShowUsername)), n.Message)
assert.Equal(t, "Custom message", n.Message)
default:
assert.Fail(t, "should not receive any other push notification types")
}

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

@@ -1344,20 +1344,28 @@ func TestHookNotificationWillBePushed(t *testing.T) {
}
tests := []struct {
name string
testCode string
expectedNotifications int
name string
testCode string
expectedNotifications int
expectedNotificationMessage string
}{
{
name: "successfully pushed",
testCode: `return false`,
testCode: `return nil, ""`,
expectedNotifications: 6,
},
{
name: "push notification rejected",
testCode: `return true`,
testCode: `return nil, "rejected"`,
expectedNotifications: 0,
},
{
name: "push notification modified",
testCode: `notification.Message = "brand new message"
return notification, ""`,
expectedNotifications: 6,
expectedNotificationMessage: "brand new message",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
@@ -1440,7 +1448,11 @@ func TestHookNotificationWillBePushed(t *testing.T) {
case model.PushTypeMessage:
numMessages++
assert.Equal(t, th.BasicChannel.Id, n.ChannelId)
assert.Contains(t, n.Message, "mentioned you")
if tt.expectedNotificationMessage != "" {
assert.Equal(t, tt.expectedNotificationMessage, n.Message)
} else {
assert.Contains(t, n.Message, "mentioned you")
}
default:
assert.Fail(t, "should not receive any other push notification types")
}

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

@@ -1,15 +1,15 @@
package main
import (
"github.com/mattermost/mattermost/server/public/plugin"
"github.com/mattermost/mattermost/server/public/model"
"github.com/mattermost/mattermost/server/public/model"
"github.com/mattermost/mattermost/server/public/plugin"
)
type MyPlugin struct {
plugin.MattermostPlugin
}
func (p *MyPlugin) NotificationWillBePushed(notification *model.PluginPushNotification) (cancel bool) {
func (p *MyPlugin) NotificationWillBePushed(notification *model.PushNotification, userID string) (*model.PushNotification, string) {
%s
}