Unverified Commit 6c7dc2d2 authored by JoramWilander's avatar JoramWilander

Merge branch 'plugins-2'

parents c042ffa4 1e1a5e5e
......@@ -7,6 +7,15 @@
revision = "2600fb119af974220d3916a5916d6e31176aac1b"
version = "v1.0.1"
[[projects]]
branch = "master"
name = "github.com/alecthomas/template"
packages = [
".",
"parse"
]
revision = "a0175ee3bccc567396460bf5acd36800cb10c49c"
[[projects]]
branch = "master"
name = "github.com/armon/go-metrics"
......@@ -112,7 +121,13 @@
[[projects]]
name = "github.com/golang/protobuf"
packages = ["proto"]
packages = [
"proto",
"ptypes",
"ptypes/any",
"ptypes/duration",
"ptypes/timestamp"
]
revision = "b4deda0973fb4c70b50d226b1af49f3da59f5265"
version = "v1.1.0"
......@@ -158,6 +173,12 @@
packages = ["."]
revision = "7554cd9344cec97297fa6649b055a8c98c2a1e55"
[[projects]]
branch = "master"
name = "github.com/hashicorp/go-hclog"
packages = ["."]
revision = "69ff559dc25f3b435631604f573a5fa1efdb6433"
[[projects]]
branch = "master"
name = "github.com/hashicorp/go-immutable-radix"
......@@ -176,6 +197,12 @@
packages = ["."]
revision = "b7773ae218740a7be65057fc60b366a49b538a44"
[[projects]]
branch = "master"
name = "github.com/hashicorp/go-plugin"
packages = ["."]
revision = "e8d22c780116115ae5624720c9af0c97afe4f551"
[[projects]]
branch = "master"
name = "github.com/hashicorp/go-sockaddr"
......@@ -214,6 +241,12 @@
packages = ["."]
revision = "2288bf30e9c8d7b5f6549bf62e07120d72fd4b6c"
[[projects]]
branch = "master"
name = "github.com/hashicorp/yamux"
packages = ["."]
revision = "2658be15c5f05e76244154714161f17e3e77de2e"
[[projects]]
branch = "master"
name = "github.com/icrowley/fake"
......@@ -330,6 +363,12 @@
packages = ["."]
revision = "3864e76763d94a6df2f9960b16a20a33da9f9a66"
[[projects]]
branch = "master"
name = "github.com/mitchellh/go-testing-interface"
packages = ["."]
revision = "a61a99592b77c9ba629d254a693acffaeb4b7e28"
[[projects]]
branch = "master"
name = "github.com/mitchellh/mapstructure"
......@@ -347,6 +386,12 @@
revision = "0dc1626d56435e9d605a29875701721c54bc9bbd"
version = "v1.10.0"
[[projects]]
name = "github.com/oklog/run"
packages = ["."]
revision = "4dadeb3030eda0273a12382bb2348ffc7c9d1a39"
version = "v1.0.0"
[[projects]]
branch = "master"
name = "github.com/olekukonko/tablewriter"
......@@ -581,15 +626,20 @@
name = "golang.org/x/net"
packages = [
"bpf",
"context",
"html",
"html/atom",
"html/charset",
"http/httpguts",
"http2",
"http2/hpack",
"idna",
"internal/iana",
"internal/socket",
"internal/timeseries",
"ipv4",
"ipv6"
"ipv6",
"trace"
]
revision = "afe8f62b1d6bbd81f31868121a50b06d8188e1f9"
......@@ -642,6 +692,45 @@
revision = "b1f26356af11148e710935ed1ac8a7f5702c7612"
version = "v1.1.0"
[[projects]]
branch = "master"
name = "google.golang.org/genproto"
packages = ["googleapis/rpc/status"]
revision = "4065a77fc542a455295382a23a996a08ed18813a"
[[projects]]
name = "google.golang.org/grpc"
packages = [
".",
"balancer",
"balancer/base",
"balancer/roundrobin",
"channelz",
"codes",
"connectivity",
"credentials",
"encoding",
"encoding/proto",
"grpclb/grpc_lb_v1/messages",
"grpclog",
"health",
"health/grpc_health_v1",
"internal",
"keepalive",
"metadata",
"naming",
"peer",
"resolver",
"resolver/dns",
"resolver/passthrough",
"stats",
"status",
"tap",
"transport"
]
revision = "41344da2231b913fa3d983840a57a6b1b7b631a1"
version = "v1.12.0"
[[projects]]
branch = "v3"
name = "gopkg.in/alexcesaro/quotedprintable.v3"
......@@ -685,6 +774,6 @@
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "76d5a63bc94bc0a75fe311cbc1df579fdd77b5d039a006236c00ee122ab69c1b"
inputs-digest = "2147cb986b5e1ba46b0c4479601fd9829cc46ccbc1bf4e8b9e59dfe0cccad77e"
solver-name = "gps-cdcl"
solver-version = 1
......@@ -282,31 +282,11 @@ ldap-mocks: ## Creates mock files for ldap.
plugin-mocks: ## Creates mock files for plugins.
go get github.com/vektra/mockery/...
$(GOPATH)/bin/mockery -dir plugin -name API -output plugin/plugintest -outpkg plugintest -case underscore -note 'Regenerate this file using `make plugin-mocks`.'
$(GOPATH)/bin/mockery -dir plugin -name KeyValueStore -output plugin/plugintest -outpkg plugintest -case underscore -note 'Regenerate this file using `make plugin-mocks`.'
$(GOPATH)/bin/mockery -dir plugin -name API -inpkg -output plugin -testonly -outpkg plugin -case underscore -note 'Regenerate this file using `make plugin-mocks`.'
$(GOPATH)/bin/mockery -dir plugin -name Hooks -output plugin/plugintest -outpkg plugintest -case underscore -note 'Regenerate this file using `make plugin-mocks`.'
@sed -i'' -e 's|API|APIMOCKINTERNAL|g' plugin/plugintest/api.go
update-jira-plugin: ## Updates Jira plugin.
go get github.com/mattermost/go-bindata/...
curl -s https://api.github.com/repos/mattermost/mattermost-plugin-jira/releases/latest | grep browser_download_url | grep darwin-amd64 | cut -d '"' -f 4 | wget -qi - -O plugin.tar.gz
$(shell go env GOPATH)/bin/go-bindata -pkg jira -o app/plugin/jira/plugin_darwin_amd64.go plugin.tar.gz
curl -s https://api.github.com/repos/mattermost/mattermost-plugin-jira/releases/latest | grep browser_download_url | grep linux-amd64 | cut -d '"' -f 4 | wget -qi - -O plugin.tar.gz
$(shell go env GOPATH)/bin/go-bindata -pkg jira -o app/plugin/jira/plugin_linux_amd64.go plugin.tar.gz
curl -s https://api.github.com/repos/mattermost/mattermost-plugin-jira/releases/latest | grep browser_download_url | grep windows-amd64 | cut -d '"' -f 4 | wget -qi - -O plugin.tar.gz
$(shell go env GOPATH)/bin/go-bindata -pkg jira -o app/plugin/jira/plugin_windows_amd64.go plugin.tar.gz
rm plugin.tar.gz
gofmt -s -w ./app/plugin/jira
update-zoom-plugin: ## Updates Zoom plugin.
go get github.com/mattermost/go-bindata/...
curl -s https://api.github.com/repos/mattermost/mattermost-plugin-zoom/releases/latest | grep browser_download_url | grep darwin-amd64 | cut -d '"' -f 4 | wget -qi - -O plugin.tar.gz
$(shell go env GOPATH)/bin/go-bindata -pkg zoom -o app/plugin/zoom/plugin_darwin_amd64.go plugin.tar.gz
curl -s https://api.github.com/repos/mattermost/mattermost-plugin-zoom/releases/latest | grep browser_download_url | grep linux-amd64 | cut -d '"' -f 4 | wget -qi - -O plugin.tar.gz
$(shell go env GOPATH)/bin/go-bindata -pkg zoom -o app/plugin/zoom/plugin_linux_amd64.go plugin.tar.gz
curl -s https://api.github.com/repos/mattermost/mattermost-plugin-zoom/releases/latest | grep browser_download_url | grep windows-amd64 | cut -d '"' -f 4 | wget -qi - -O plugin.tar.gz
$(shell go env GOPATH)/bin/go-bindata -pkg zoom -o app/plugin/zoom/plugin_windows_amd64.go plugin.tar.gz
rm plugin.tar.gz
gofmt -s -w ./app/plugin/zoom
pluginapi: ## Generates api and hooks glue code for plugins
go generate ./plugin
check-licenses: ## Checks license status.
./scripts/license-check.sh $(TE_PACKAGES) $(EE_PACKAGES)
......
......@@ -49,6 +49,7 @@ type TestHelper struct {
SystemAdminClient *model.Client4
SystemAdminUser *model.User
tempWorkspace string
}
type persistentTestStore struct {
......@@ -137,6 +138,25 @@ func setupTestHelper(enterprise bool) *TestHelper {
th.Client = th.CreateClient()
th.SystemAdminClient = th.CreateClient()
if th.tempWorkspace == "" {
dir, err := ioutil.TempDir("", "apptest")
if err != nil {
panic(err)
}
th.tempWorkspace = dir
}
pluginDir := filepath.Join(th.tempWorkspace, "plugins")
webappDir := filepath.Join(th.tempWorkspace, "webapp")
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.PluginSettings.Directory = pluginDir
*cfg.PluginSettings.ClientDirectory = webappDir
})
th.App.InitPlugins(pluginDir, webappDir)
return th
}
......
......@@ -1931,9 +1931,6 @@ func TestRemoveChannelMember(t *testing.T) {
t.Fatal("should have passed")
}
_, resp = Client.RemoveUserFromChannel(th.BasicChannel.Id, th.BasicUser2.Id)
CheckNoError(t, resp)
_, resp = Client.RemoveUserFromChannel(th.BasicChannel.Id, "junk")
CheckBadRequestStatus(t, resp)
......
......@@ -24,11 +24,10 @@ func (api *API) InitPlugin() {
api.BaseRoutes.Plugin.Handle("", api.ApiSessionRequired(removePlugin)).Methods("DELETE")
api.BaseRoutes.Plugins.Handle("/statuses", api.ApiSessionRequired(getPluginStatuses)).Methods("GET")
api.BaseRoutes.Plugin.Handle("/activate", api.ApiSessionRequired(activatePlugin)).Methods("POST")
api.BaseRoutes.Plugin.Handle("/deactivate", api.ApiSessionRequired(deactivatePlugin)).Methods("POST")
api.BaseRoutes.Plugin.Handle("/enable", api.ApiSessionRequired(enablePlugin)).Methods("POST")
api.BaseRoutes.Plugin.Handle("/disable", api.ApiSessionRequired(disablePlugin)).Methods("POST")
api.BaseRoutes.Plugins.Handle("/webapp", api.ApiHandler(getWebappPlugins)).Methods("GET")
}
func uploadPlugin(c *Context, w http.ResponseWriter, r *http.Request) {
......@@ -165,7 +164,7 @@ func getWebappPlugins(c *Context, w http.ResponseWriter, r *http.Request) {
w.Write([]byte(model.ManifestListToJson(clientManifests)))
}
func activatePlugin(c *Context, w http.ResponseWriter, r *http.Request) {
func enablePlugin(c *Context, w http.ResponseWriter, r *http.Request) {
c.RequirePluginId()
if c.Err != nil {
return
......@@ -189,7 +188,7 @@ func activatePlugin(c *Context, w http.ResponseWriter, r *http.Request) {
ReturnStatusOK(w)
}
func deactivatePlugin(c *Context, w http.ResponseWriter, r *http.Request) {
func disablePlugin(c *Context, w http.ResponseWriter, r *http.Request) {
c.RequirePluginId()
if c.Err != nil {
return
......
......@@ -6,7 +6,6 @@ package api4
import (
"bytes"
"encoding/json"
"io/ioutil"
"os"
"path/filepath"
"testing"
......@@ -14,18 +13,9 @@ import (
"github.com/mattermost/mattermost-server/model"
"github.com/mattermost/mattermost-server/utils"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestPlugin(t *testing.T) {
pluginDir, err := ioutil.TempDir("", "mm-plugin-test")
require.NoError(t, err)
defer os.RemoveAll(pluginDir)
webappDir, err := ioutil.TempDir("", "mm-webapp-test")
require.NoError(t, err)
defer os.RemoveAll(webappDir)
th := Setup().InitBasic().InitSystemAdmin()
defer th.TearDown()
......@@ -47,12 +37,6 @@ func TestPlugin(t *testing.T) {
*cfg.PluginSettings.EnableUploads = true
})
th.App.InitPlugins(pluginDir, webappDir, nil)
defer func() {
th.App.ShutDownPlugins()
th.App.PluginEnv = nil
}()
path, _ := utils.FindDir("tests")
file, err := os.Open(filepath.Join(path, "testplugin.tar.gz"))
if err != nil {
......@@ -109,7 +93,7 @@ func TestPlugin(t *testing.T) {
assert.False(t, found)
// Successful activate
ok, resp := th.SystemAdminClient.ActivatePlugin(manifest.Id)
ok, resp := th.SystemAdminClient.EnablePlugin(manifest.Id)
CheckNoError(t, resp)
assert.True(t, ok)
......@@ -126,12 +110,12 @@ func TestPlugin(t *testing.T) {
assert.True(t, found)
// Activate error case
ok, resp = th.SystemAdminClient.ActivatePlugin("junk")
ok, resp = th.SystemAdminClient.EnablePlugin("junk")
CheckBadRequestStatus(t, resp)
assert.False(t, ok)
// Successful deactivate
ok, resp = th.SystemAdminClient.DeactivatePlugin(manifest.Id)
ok, resp = th.SystemAdminClient.DisablePlugin(manifest.Id)
CheckNoError(t, resp)
assert.True(t, ok)
......@@ -148,7 +132,7 @@ func TestPlugin(t *testing.T) {
assert.True(t, found)
// Deactivate error case
ok, resp = th.SystemAdminClient.DeactivatePlugin("junk")
ok, resp = th.SystemAdminClient.DisablePlugin("junk")
CheckBadRequestStatus(t, resp)
assert.False(t, ok)
......@@ -162,7 +146,7 @@ func TestPlugin(t *testing.T) {
CheckForbiddenStatus(t, resp)
// Successful webapp get
_, resp = th.SystemAdminClient.ActivatePlugin(manifest.Id)
_, resp = th.SystemAdminClient.EnablePlugin(manifest.Id)
CheckNoError(t, resp)
manifests, resp := th.Client.GetWebappPlugins()
......
......@@ -25,7 +25,7 @@ import (
tjobs "github.com/mattermost/mattermost-server/jobs/interfaces"
"github.com/mattermost/mattermost-server/mlog"
"github.com/mattermost/mattermost-server/model"
"github.com/mattermost/mattermost-server/plugin/pluginenv"
"github.com/mattermost/mattermost-server/plugin"
"github.com/mattermost/mattermost-server/store"
"github.com/mattermost/mattermost-server/store/sqlstore"
"github.com/mattermost/mattermost-server/utils"
......@@ -42,10 +42,8 @@ type App struct {
Log *mlog.Logger
PluginEnv *pluginenv.Environment
PluginConfigListenerId string
IsPluginSandboxSupported bool
pluginStatuses map[string]*model.PluginStatus
Plugins *plugin.Environment
PluginConfigListenerId string
EmailBatching *EmailBatchingJob
EmailRateLimiter *throttled.GCRARateLimiter
......@@ -242,8 +240,6 @@ func New(options ...Option) (outApp *App, outErr error) {
handlers: make(map[string]webSocketHandler),
}
app.initBuiltInPlugins()
return app, nil
}
......
......@@ -4,23 +4,21 @@
package app
import (
"encoding/json"
"io"
"io/ioutil"
"os"
"path/filepath"
"time"
"testing"
"github.com/mattermost/mattermost-server/einterfaces"
"github.com/mattermost/mattermost-server/mlog"
"github.com/mattermost/mattermost-server/model"
"github.com/mattermost/mattermost-server/plugin"
"github.com/mattermost/mattermost-server/plugin/pluginenv"
"github.com/mattermost/mattermost-server/store"
"github.com/mattermost/mattermost-server/store/sqlstore"
"github.com/mattermost/mattermost-server/store/storetest"
"github.com/mattermost/mattermost-server/utils"
"testing"
)
type TestHelper struct {
......@@ -35,7 +33,6 @@ type TestHelper struct {
tempConfigPath string
tempWorkspace string
pluginHooks map[string]plugin.Hooks
}
type persistentTestStore struct {
......@@ -93,7 +90,6 @@ func setupTestHelper(enterprise bool) *TestHelper {
th := &TestHelper{
App: a,
pluginHooks: make(map[string]plugin.Hooks),
tempConfigPath: tempConfig.Name(),
}
......@@ -123,6 +119,19 @@ func setupTestHelper(enterprise bool) *TestHelper {
th.App.SetLicense(nil)
}
if th.tempWorkspace == "" {
dir, err := ioutil.TempDir("", "apptest")
if err != nil {
panic(err)
}
th.tempWorkspace = dir
}
pluginDir := filepath.Join(th.tempWorkspace, "plugins")
webappDir := filepath.Join(th.tempWorkspace, "webapp")
th.App.InitPlugins(pluginDir, webappDir)
return th
}
......@@ -382,65 +391,6 @@ func (me *TestHelper) TearDown() {
}
}
type mockPluginSupervisor struct {
hooks plugin.Hooks
}
func (s *mockPluginSupervisor) Start(api plugin.API) error {
return s.hooks.OnActivate(api)
}
func (s *mockPluginSupervisor) Wait() error {
return nil
}
func (s *mockPluginSupervisor) Stop() error {
return nil
}
func (s *mockPluginSupervisor) Hooks() plugin.Hooks {
return s.hooks
}
func (me *TestHelper) InstallPlugin(manifest *model.Manifest, hooks plugin.Hooks) {
if me.tempWorkspace == "" {
dir, err := ioutil.TempDir("", "apptest")
if err != nil {
panic(err)
}
me.tempWorkspace = dir
}
manifestCopy := *manifest
if manifestCopy.Backend == nil {
manifestCopy.Backend = &model.ManifestBackend{}
}
manifestBytes, err := json.Marshal(&manifestCopy)
if err != nil {
panic(err)
}
pluginDir := filepath.Join(me.tempWorkspace, "plugins")
webappDir := filepath.Join(me.tempWorkspace, "webapp")
if err := os.MkdirAll(filepath.Join(pluginDir, manifest.Id), 0700); err != nil {
panic(err)
}
if err := ioutil.WriteFile(filepath.Join(pluginDir, manifest.Id, "plugin.json"), manifestBytes, 0600); err != nil {
panic(err)
}
me.App.InitPlugins(pluginDir, webappDir, func(bundle *model.BundleInfo) (plugin.Supervisor, error) {
if hooks, ok := me.pluginHooks[bundle.Manifest.Id]; ok {
return &mockPluginSupervisor{hooks}, nil
}
return pluginenv.DefaultSupervisorProvider(bundle)
})
me.pluginHooks[manifest.Id] = hooks
}
func (me *TestHelper) ResetRoleMigration() {
if _, err := testStoreSqlSupplier.GetMaster().Exec("DELETE from Roles"); err != nil {
panic(err)
......
......@@ -11,6 +11,7 @@ import (
"github.com/mattermost/mattermost-server/mlog"
"github.com/mattermost/mattermost-server/model"
"github.com/mattermost/mattermost-server/plugin"
"github.com/mattermost/mattermost-server/store"
"github.com/mattermost/mattermost-server/utils"
)
......@@ -183,6 +184,16 @@ func (a *App) CreateChannel(channel *model.Channel, addMember bool) (*model.Chan
a.InvalidateCacheForUser(channel.CreatorId)
}
if a.PluginsReady() {
a.Go(func() {
pluginContext := &plugin.Context{}
a.Plugins.RunMultiPluginHook(func(hooks plugin.Hooks) bool {
hooks.ChannelHasBeenCreated(pluginContext, sc)
return true
}, plugin.ChannelHasBeenCreatedId)
})
}
return sc, nil
}
}
......@@ -200,6 +211,16 @@ func (a *App) CreateDirectChannel(userId string, otherUserId string) (*model.Cha
a.InvalidateCacheForUser(userId)
a.InvalidateCacheForUser(otherUserId)
if a.PluginsReady() {
a.Go(func() {
pluginContext := &plugin.Context{}
a.Plugins.RunMultiPluginHook(func(hooks plugin.Hooks) bool {
hooks.ChannelHasBeenCreated(pluginContext, channel)
return true
}, plugin.ChannelHasBeenCreatedId)
})
}
message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_DIRECT_ADDED, "", channel.Id, "", nil)
message.Add("teammate_id", otherUserId)
a.Publish(message)
......@@ -798,6 +819,16 @@ func (a *App) AddChannelMember(userId string, channel *model.Channel, userReques
return nil, err
}
if a.PluginsReady() {
a.Go(func() {
pluginContext := &plugin.Context{}
a.Plugins.RunMultiPluginHook(func(hooks plugin.Hooks) bool {
hooks.UserHasJoinedChannel(pluginContext, cm, userRequestor)
return true
}, plugin.UserHasJoinedChannelId)
})
}