diff --git a/server/channels/app/post.go b/server/channels/app/post.go index 416188e838..15823e3178 100644 --- a/server/channels/app/post.go +++ b/server/channels/app/post.go @@ -702,7 +702,7 @@ func (a *App) UpdatePost(c *request.Context, receivedUpdatedPost *model.Post, sa pluginContext := pluginContext(c) a.ch.RunMultiHook(func(hooks plugin.Hooks) bool { newPost, rejectionReason = hooks.MessageWillBeUpdated(pluginContext, newPost.ForPlugin(), oldPost.ForPlugin()) - return receivedUpdatedPost != nil + return newPost != nil }, plugin.MessageWillBeUpdatedID) if newPost == nil { return nil, model.NewAppError("UpdatePost", "Post rejected by plugin. "+rejectionReason, nil, "", http.StatusBadRequest) diff --git a/server/channels/app/post_test.go b/server/channels/app/post_test.go index 3f76e43e0c..e89257ff77 100644 --- a/server/channels/app/post_test.go +++ b/server/channels/app/post_test.go @@ -404,6 +404,147 @@ func TestPostAttachPostToChildPost(t *testing.T) { assert.Nil(t, err) } +func TestUpdatePostPluginHooks(t *testing.T) { + th := Setup(t).InitBasic() + defer th.TearDown() + + t.Run("Should stop processing at first reject", func(t *testing.T) { + setupMultiPluginAPITest(t, []string{ + ` + package main + + import ( + "github.com/mattermost/mattermost/server/public/plugin" + "github.com/mattermost/mattermost/server/public/model" + ) + + type MyPlugin struct { + plugin.MattermostPlugin + } + + func (p *MyPlugin) MessageWillBeUpdated(c *plugin.Context, newPost, oldPost *model.Post) (*model.Post, string) { + return nil, "rejected" + } + + func main() { + plugin.ClientMain(&MyPlugin{}) + } + `, + ` + package main + + import ( + "github.com/mattermost/mattermost/server/public/plugin" + "github.com/mattermost/mattermost/server/public/model" + ) + + type MyPlugin struct { + plugin.MattermostPlugin + } + + func (p *MyPlugin) MessageWillBeUpdated(c *plugin.Context, newPost, oldPost *model.Post) (*model.Post, string) { + if (newPost == nil) { + return nil, "nil post" + } + newPost.Message = newPost.Message + "fromplugin" + return newPost, "" + } + + func main() { + plugin.ClientMain(&MyPlugin{}) + } + `, + }, []string{ + `{"id": "testrejectfirstpost", "server": {"executable": "backend.exe"}}`, + `{"id": "testupdatepost", "server": {"executable": "backend.exe"}}`, + }, []string{ + "testrejectfirstpost", "testupdatepost", + }, true, th.App, th.Context) + + pendingPostId := model.NewId() + post, err := th.App.CreatePostAsUser(th.Context, &model.Post{ + UserId: th.BasicUser.Id, + ChannelId: th.BasicChannel.Id, + Message: "message", + PendingPostId: pendingPostId, + }, "", true) + require.Nil(t, err) + + post.Message = "new message" + updatedPost, err := th.App.UpdatePost(th.Context, post, false) + require.Nil(t, updatedPost) + require.NotNil(t, err) + require.Equal(t, "Post rejected by plugin. rejected", err.Id) + }) + + t.Run("Should update", func(t *testing.T) { + setupMultiPluginAPITest(t, []string{ + ` + package main + + import ( + "github.com/mattermost/mattermost/server/public/plugin" + "github.com/mattermost/mattermost/server/public/model" + ) + + type MyPlugin struct { + plugin.MattermostPlugin + } + + func (p *MyPlugin) MessageWillBeUpdated(c *plugin.Context, newPost, oldPost *model.Post) (*model.Post, string) { + newPost.Message = newPost.Message + " 1" + return newPost, "" + } + + func main() { + plugin.ClientMain(&MyPlugin{}) + } + `, + ` + package main + + import ( + "github.com/mattermost/mattermost/server/public/plugin" + "github.com/mattermost/mattermost/server/public/model" + ) + + type MyPlugin struct { + plugin.MattermostPlugin + } + + func (p *MyPlugin) MessageWillBeUpdated(c *plugin.Context, newPost, oldPost *model.Post) (*model.Post, string) { + newPost.Message = newPost.Message + " 2" + return newPost, "" + } + + func main() { + plugin.ClientMain(&MyPlugin{}) + } + `, + }, []string{ + `{"id": "testaddone", "server": {"executable": "backend.exe"}}`, + `{"id": "testaddtwo", "server": {"executable": "backend.exe"}}`, + }, []string{ + "testaddone", "testaddtwo", + }, true, th.App, th.Context) + + pendingPostId := model.NewId() + post, err := th.App.CreatePostAsUser(th.Context, &model.Post{ + UserId: th.BasicUser.Id, + ChannelId: th.BasicChannel.Id, + Message: "message", + PendingPostId: pendingPostId, + }, "", true) + require.Nil(t, err) + + post.Message = "new message" + updatedPost, err := th.App.UpdatePost(th.Context, post, false) + require.Nil(t, err) + require.NotNil(t, updatedPost) + require.Equal(t, "new message 1 2", updatedPost.Message) + }) +} + func TestPostChannelMentions(t *testing.T) { th := Setup(t).InitBasic() defer th.TearDown() diff --git a/server/public/plugin/client_rpc.go b/server/public/plugin/client_rpc.go index c31aefc7a3..0aef4c253a 100644 --- a/server/public/plugin/client_rpc.go +++ b/server/public/plugin/client_rpc.go @@ -678,13 +678,16 @@ type Z_MessageWillBeUpdatedReturns struct { func (g *hooksRPCClient) MessageWillBeUpdated(c *Context, newPost, oldPost *model.Post) (*model.Post, string) { _args := &Z_MessageWillBeUpdatedArgs{c, newPost, oldPost} - _returns := &Z_MessageWillBeUpdatedReturns{A: _args.B} + _default_returns := &Z_MessageWillBeUpdatedReturns{A: _args.B} if g.implemented[MessageWillBeUpdatedID] { + _returns := &Z_MessageWillBeUpdatedReturns{} if err := g.client.Call("Plugin.MessageWillBeUpdated", _args, _returns); err != nil { g.log.Error("RPC call MessageWillBeUpdated to plugin failed.", mlog.Err(err)) + return _default_returns.A, _default_returns.B } + return _returns.A, _returns.B } - return _returns.A, _returns.B + return _default_returns.A, _default_returns.B } func (s *hooksRPCServer) MessageWillBeUpdated(args *Z_MessageWillBeUpdatedArgs, returns *Z_MessageWillBeUpdatedReturns) error {