Skip to content

Commit

Permalink
MM-11024 Migrate to use plugin v2 system coming in Mattermost 5.2 (#1)
Browse files Browse the repository at this point in the history
* Migrate to use plugin v2 system coming in Mattermost 5.2

* Update glide
  • Loading branch information
jwilander authored Jul 16, 2018
1 parent f8c6c1d commit 19a26d0
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 67 deletions.
101 changes: 94 additions & 7 deletions glide.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions main.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package main

import (
"github.com/mattermost/mattermost-server/plugin/rpcplugin"
"github.com/mattermost/mattermost-server/plugin"
)

func main() {
rpcplugin.Main(&Plugin{})
plugin.ClientMain(&Plugin{})
}
41 changes: 10 additions & 31 deletions plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,42 +4,21 @@ import (
"crypto/subtle"
"encoding/json"
"net/http"
"sync/atomic"

"github.com/mattermost/mattermost-server/model"
"github.com/mattermost/mattermost-server/plugin"
)

type Configuration struct {
type Plugin struct {
plugin.MattermostPlugin

Enabled bool
Secret string
UserName string
}

type Plugin struct {
api plugin.API
configuration atomic.Value
}

func (p *Plugin) OnActivate(api plugin.API) error {
p.api = api
return p.OnConfigurationChange()
}

func (p *Plugin) config() *Configuration {
return p.configuration.Load().(*Configuration)
}

func (p *Plugin) OnConfigurationChange() error {
var configuration Configuration
err := p.api.LoadPluginConfiguration(&configuration)
p.configuration.Store(&configuration)
return err
}

func (p *Plugin) ServeHTTP(w http.ResponseWriter, r *http.Request) {
config := p.config()
if !config.Enabled || config.Secret == "" || config.UserName == "" {
func (p *Plugin) ServeHTTP(c *plugin.Context, w http.ResponseWriter, r *http.Request) {
if !p.Enabled || p.Secret == "" || p.UserName == "" {
http.Error(w, "This plugin is not configured.", http.StatusForbidden)
return
} else if r.URL.Path != "/webhook" {
Expand All @@ -48,7 +27,7 @@ func (p *Plugin) ServeHTTP(w http.ResponseWriter, r *http.Request) {
} else if r.Method != http.MethodPost {
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
return
} else if subtle.ConstantTimeCompare([]byte(r.URL.Query().Get("secret")), []byte(config.Secret)) != 1 {
} else if subtle.ConstantTimeCompare([]byte(r.URL.Query().Get("secret")), []byte(p.Secret)) != 1 {
http.Error(w, "You must provide the configured secret.", http.StatusForbidden)
return
}
Expand All @@ -63,13 +42,13 @@ func (p *Plugin) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return
} else if r.URL.Query().Get("channel") == "" {
http.Error(w, "You must provide a channel.", http.StatusBadRequest)
} else if user, err := p.api.GetUserByUsername(config.UserName); err != nil {
} else if user, err := p.API.GetUserByUsername(p.UserName); err != nil {
http.Error(w, err.Message, err.StatusCode)
} else if team, err := p.api.GetTeamByName(r.URL.Query().Get("team")); err != nil {
} else if team, err := p.API.GetTeamByName(r.URL.Query().Get("team")); err != nil {
http.Error(w, err.Message, err.StatusCode)
} else if channel, err := p.api.GetChannelByName(r.URL.Query().Get("channel"), team.Id); err != nil {
} else if channel, err := p.API.GetChannelByName(r.URL.Query().Get("channel"), team.Id); err != nil {
http.Error(w, err.Message, err.StatusCode)
} else if _, err := p.api.CreatePost(&model.Post{
} else if _, err := p.API.CreatePost(&model.Post{
ChannelId: channel.Id,
Type: model.POST_SLACK_ATTACHMENT,
UserId: user.Id,
Expand Down
2 changes: 1 addition & 1 deletion plugin.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ backend:
executable: plugin.exe
name: JIRA
description: Receives webhook events from JIRA and makes Mattermost posts for them.
version: '0.1.2'
version: '1.0.0'
settings_schema:
settings:
- key: Enabled
Expand Down
44 changes: 18 additions & 26 deletions plugin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
Expand All @@ -15,6 +14,7 @@ import (
"github.com/stretchr/testify/require"

"github.com/mattermost/mattermost-server/model"
"github.com/mattermost/mattermost-server/plugin"
"github.com/mattermost/mattermost-server/plugin/plugintest"
"github.com/mattermost/mattermost-server/plugin/plugintest/mock"
)
Expand All @@ -27,40 +27,38 @@ func validRequestBody() io.ReadCloser {
}
}

type TestConfiguration struct {
Enabled bool
Secret string
UserName string
}

func TestPlugin(t *testing.T) {
f, err := os.Open("testdata/webhook_issue_created.json")
require.NoError(t, err)
defer f.Close()
var webhook Webhook
require.NoError(t, json.NewDecoder(f).Decode(&webhook))
expectedAttachment, err := webhook.SlackAttachment()
require.NoError(t, err)

validConfiguration := Configuration{
validConfiguration := TestConfiguration{
Enabled: true,
Secret: "thesecret",
UserName: "theuser",
}

for name, tc := range map[string]struct {
Configuration Configuration
ConfigurationError error
Configuration TestConfiguration
Request *http.Request
CreatePostError *model.AppError
ExpectedStatusCode int
}{
"NoConfiguration": {
Configuration: Configuration{},
Request: httptest.NewRequest("POST", "/webhook?team=theteam&channel=thechannel&secret=thesecret", validRequestBody()),
ExpectedStatusCode: http.StatusForbidden,
},
"ConfigurationError": {
ConfigurationError: fmt.Errorf("foo"),
Configuration: TestConfiguration{},
Request: httptest.NewRequest("POST", "/webhook?team=theteam&channel=thechannel&secret=thesecret", validRequestBody()),
ExpectedStatusCode: http.StatusForbidden,
},
"NoUserConfiguration": {
Configuration: Configuration{
Configuration: TestConfiguration{
Enabled: true,
Secret: "thesecret",
},
Expand Down Expand Up @@ -98,7 +96,7 @@ func TestPlugin(t *testing.T) {
ExpectedStatusCode: http.StatusBadRequest,
},
"InvalidUser": {
Configuration: Configuration{
Configuration: TestConfiguration{
Enabled: true,
Secret: "thesecret",
UserName: "nottheuser",
Expand Down Expand Up @@ -131,11 +129,6 @@ func TestPlugin(t *testing.T) {
t.Run(name, func(t *testing.T) {
api := &plugintest.API{}

api.On("LoadPluginConfiguration", mock.AnythingOfType("*main.Configuration")).Return(func(dest interface{}) error {
*dest.(*Configuration) = tc.Configuration
return tc.ConfigurationError
})

api.On("GetUserByUsername", "theuser").Return(&model.User{
Id: "theuserid",
}, (*model.AppError)(nil))
Expand All @@ -147,22 +140,21 @@ func TestPlugin(t *testing.T) {
api.On("GetTeamByName", "nottheteam").Return((*model.Team)(nil), model.NewAppError("foo", "bar", nil, "", http.StatusBadRequest))

api.On("GetChannelByName", "thechannel", "theteamid").Run(func(args mock.Arguments) {
api.On("CreatePost", mock.AnythingOfType("*model.Post")).Return(func(post *model.Post) (*model.Post, *model.AppError) {
assert.Equal(t, post.ChannelId, "thechannelid")
assert.Equal(t, post.Props["attachments"], []*model.SlackAttachment{expectedAttachment})
return &model.Post{}, tc.CreatePostError
})
api.On("CreatePost", mock.AnythingOfType("*model.Post")).Return(&model.Post{}, tc.CreatePostError)
}).Return(&model.Channel{
Id: "thechannelid",
TeamId: "theteamid",
}, (*model.AppError)(nil))
api.On("GetChannelByName", "notthechannel", "theteamid").Return((*model.Channel)(nil), model.NewAppError("foo", "bar", nil, "", http.StatusBadRequest))

p := Plugin{}
p.OnActivate(api)
p.Enabled = tc.Configuration.Enabled
p.Secret = tc.Configuration.Secret
p.UserName = tc.Configuration.UserName
p.SetAPI(api)

w := httptest.NewRecorder()
p.ServeHTTP(w, tc.Request)
p.ServeHTTP(&plugin.Context{}, w, tc.Request)
assert.Equal(t, tc.ExpectedStatusCode, w.Result().StatusCode)
})
}
Expand Down

0 comments on commit 19a26d0

Please sign in to comment.