From 4ce7b92283aaa3ca56470891e6728c98a2a63df0 Mon Sep 17 00:00:00 2001 From: Jesse Hallam Date: Tue, 17 Sep 2019 16:02:26 -0300 Subject: [PATCH] MM-17023: Plugin Marketplace (#12183) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * MM-17149 - Extend config.json for marketplace settings (#11933) * MM-17149 - Extend config.json for marketplace settings * Renamed MarketplaceUrl, tracking default marketplace url * Added EnableMarketplace to the client config * Revert "Added EnableMarketplace to the client config" This reverts commit 0f982c4c661c2cd9bb96264e9a01a2363c40d9c5. * MM-17149 - Added EnableMarketplace to the client config (#11958) * Added EnableMarketplace to the client config * Moved EnableMarketplace setting out of limited client configuration * MM-17150, MM-17545, MM-18100 - Implement GET /api/v4/plugins/m… (#11977) * MM-17150 - Implement GET /api/v4/plugins/marketplace proxying upstream MM-17545 - Merge locally installed plugins into GET /api/v4/plugins/marketplace * Replaced MarketplacePluginState with Installed * Setting InstalledVersion instead of Installed * marketplace client setting per_page if non zero * Creating insecure client for marketplace url * Fixed trailing slash for default marketplace url * Adding filtering * Fixed function names * Renamed Manifest() to GetManifest(), added godoc for BaseMarketplacePlugin * Handling plugin.ErrNotFound correctly * Checking err == nil instead when a plugin is installed * MM-18450 - Local-only plugin search (#12152) * MM-17846: plugin icons (#12157) * MM-17846: add support for plugin icons Extend the model definitions to support plugin icons from the marketplace. * s/IconURL/IconData * MM-18475 - Converge on snake_case responses from the marketplace (#12179) * MM-18520 - MM-Server should forward server version to marketplace server (#12181) * Renamed request to filter client4.GetMarketplacePlugins * Renamed request to filter * Guarding against bad marketplace server response --- api4/helpers.go | 25 +++ api4/plugin.go | 62 ++++++ api4/plugin_test.go | 332 ++++++++++++++++++++++++++++++++- app/diagnostics.go | 2 + app/plugin.go | 99 ++++++++++ config/client.go | 1 + i18n/en.json | 16 ++ model/client4.go | 25 +++ model/config.go | 28 +-- model/marketplace_plugin.go | 69 +++++++ plugin/environment.go | 19 ++ services/marketplace/client.go | 79 ++++++++ tests/testpluginv2.tar.gz | Bin 0 -> 71989 bytes 13 files changed, 736 insertions(+), 21 deletions(-) create mode 100644 api4/helpers.go create mode 100644 model/marketplace_plugin.go create mode 100644 services/marketplace/client.go create mode 100644 tests/testpluginv2.tar.gz diff --git a/api4/helpers.go b/api4/helpers.go new file mode 100644 index 0000000000..6b07a279ce --- /dev/null +++ b/api4/helpers.go @@ -0,0 +1,25 @@ +// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package api4 + +import ( + "net/url" + "strconv" + + "github.com/pkg/errors" +) + +func parseInt(u *url.URL, name string, defaultValue int) (int, error) { + valueStr := u.Query().Get(name) + if valueStr == "" { + return defaultValue, nil + } + + value, err := strconv.Atoi(valueStr) + if err != nil { + return 0, errors.Wrapf(err, "failed to parse %s as integer", name) + } + + return value, nil +} diff --git a/api4/plugin.go b/api4/plugin.go index 1f045afc71..18ce219975 100644 --- a/api4/plugin.go +++ b/api4/plugin.go @@ -7,6 +7,7 @@ package api4 import ( "bytes" + "encoding/json" "io/ioutil" "net/http" "net/url" @@ -36,6 +37,8 @@ func (api *API) InitPlugin() { api.BaseRoutes.Plugin.Handle("/disable", api.ApiSessionRequired(disablePlugin)).Methods("POST") api.BaseRoutes.Plugins.Handle("/webapp", api.ApiHandler(getWebappPlugins)).Methods("GET") + + api.BaseRoutes.Plugins.Handle("/marketplace", api.ApiSessionRequired(getMarketplacePlugins)).Methods("GET") } func uploadPlugin(c *Context, w http.ResponseWriter, r *http.Request) { @@ -239,6 +242,43 @@ func getWebappPlugins(c *Context, w http.ResponseWriter, r *http.Request) { w.Write([]byte(model.ManifestListToJson(clientManifests))) } +func getMarketplacePlugins(c *Context, w http.ResponseWriter, r *http.Request) { + if !*c.App.Config().PluginSettings.Enable { + c.Err = model.NewAppError("getMarketplacePlugins", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented) + return + } + + if !*c.App.Config().PluginSettings.EnableMarketplace { + c.Err = model.NewAppError("getMarketplacePlugins", "app.plugin.marketplace_disabled.app_error", nil, "", http.StatusNotImplemented) + return + } + + if !c.App.SessionHasPermissionTo(c.App.Session, model.PERMISSION_MANAGE_SYSTEM) { + c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + return + } + + filter, err := parseMarketplacePluginFilter(r.URL) + if err != nil { + c.Err = model.NewAppError("getMarketplacePlugins", "app.plugin.marshal.app_error", nil, err.Error(), http.StatusInternalServerError) + return + } + + plugins, appErr := c.App.GetMarketplacePlugins(filter) + if appErr != nil { + c.Err = appErr + return + } + + json, err := json.Marshal(plugins) + if err != nil { + c.Err = model.NewAppError("getMarketplacePlugins", "app.plugin.marshal.app_error", nil, err.Error(), http.StatusInternalServerError) + return + } + + w.Write(json) +} + func enablePlugin(c *Context, w http.ResponseWriter, r *http.Request) { c.RequirePluginId() if c.Err != nil { @@ -286,3 +326,25 @@ func disablePlugin(c *Context, w http.ResponseWriter, r *http.Request) { ReturnStatusOK(w) } + +func parseMarketplacePluginFilter(u *url.URL) (*model.MarketplacePluginFilter, error) { + page, err := parseInt(u, "page", 0) + if err != nil { + return nil, err + } + + perPage, err := parseInt(u, "per_page", 100) + if err != nil { + return nil, err + } + + filter := u.Query().Get("filter") + serverVersion := u.Query().Get("server_version") + + return &model.MarketplacePluginFilter{ + Page: page, + PerPage: perPage, + Filter: filter, + ServerVersion: serverVersion, + }, nil +} diff --git a/api4/plugin_test.go b/api4/plugin_test.go index fef1ac3918..4dbed6ba4a 100644 --- a/api4/plugin_test.go +++ b/api4/plugin_test.go @@ -11,6 +11,8 @@ import ( "net/http/httptest" "os" "path/filepath" + "sort" + "strings" "testing" "time" @@ -36,9 +38,7 @@ func TestPlugin(t *testing.T) { path, _ := fileutils.FindDir("tests") tarData, err := ioutil.ReadFile(filepath.Join(path, "testplugin.tar.gz")) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // Install from URL testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) { @@ -270,9 +270,7 @@ func TestNotifyClusterPluginEvent(t *testing.T) { path, _ := fileutils.FindDir("tests") tarData, err := ioutil.ReadFile(filepath.Join(path, "testplugin.tar.gz")) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) testCluster.ClearMessages() @@ -331,9 +329,7 @@ func TestNotifyClusterPluginEvent(t *testing.T) { func TestDisableOnRemove(t *testing.T) { path, _ := fileutils.FindDir("tests") tarData, err := ioutil.ReadFile(filepath.Join(path, "testplugin.tar.gz")) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) testCases := []struct { Description string @@ -432,6 +428,324 @@ func TestDisableOnRemove(t *testing.T) { } } +func TestGetMarketplacePlugins(t *testing.T) { + th := Setup().InitBasic() + defer th.TearDown() + + th.App.UpdateConfig(func(cfg *model.Config) { + *cfg.PluginSettings.Enable = true + *cfg.PluginSettings.EnableUploads = true + *cfg.PluginSettings.EnableMarketplace = false + }) + + t.Run("marketplace disabled", func(t *testing.T) { + th.App.UpdateConfig(func(cfg *model.Config) { + *cfg.PluginSettings.EnableMarketplace = false + *cfg.PluginSettings.MarketplaceUrl = "invalid.com" + }) + + plugins, resp := th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{}) + CheckNotImplementedStatus(t, resp) + require.Nil(t, plugins) + }) + + t.Run("no server", func(t *testing.T) { + th.App.UpdateConfig(func(cfg *model.Config) { + *cfg.PluginSettings.EnableMarketplace = true + *cfg.PluginSettings.MarketplaceUrl = "invalid.com" + }) + + plugins, resp := th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{}) + CheckInternalErrorStatus(t, resp) + require.Nil(t, plugins) + }) + + t.Run("no permission", func(t *testing.T) { + th.App.UpdateConfig(func(cfg *model.Config) { + *cfg.PluginSettings.EnableMarketplace = true + *cfg.PluginSettings.MarketplaceUrl = "invalid.com" + }) + + plugins, resp := th.Client.GetMarketplacePlugins(&model.MarketplacePluginFilter{}) + CheckForbiddenStatus(t, resp) + require.Nil(t, plugins) + }) + + t.Run("empty response from server", func(t *testing.T) { + testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) { + res.WriteHeader(http.StatusOK) + json, err := json.Marshal([]*model.MarketplacePlugin{}) + require.NoError(t, err) + res.Write(json) + })) + defer func() { testServer.Close() }() + + th.App.UpdateConfig(func(cfg *model.Config) { + *cfg.PluginSettings.EnableMarketplace = true + *cfg.PluginSettings.MarketplaceUrl = testServer.URL + }) + + plugins, resp := th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{}) + CheckNoError(t, resp) + require.Len(t, plugins, 0) + }) + + t.Run("verify server version is passed through", func(t *testing.T) { + testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) { + serverVersion, ok := req.URL.Query()["server_version"] + require.True(t, ok) + require.Len(t, serverVersion, 1) + require.Equal(t, model.CurrentVersion, serverVersion[0]) + require.NotEqual(t, 0, len(serverVersion[0])) + + res.WriteHeader(http.StatusOK) + json, err := json.Marshal([]*model.MarketplacePlugin{}) + require.NoError(t, err) + res.Write(json) + })) + defer func() { testServer.Close() }() + + th.App.UpdateConfig(func(cfg *model.Config) { + *cfg.PluginSettings.EnableMarketplace = true + *cfg.PluginSettings.MarketplaceUrl = testServer.URL + }) + + plugins, resp := th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{}) + CheckNoError(t, resp) + require.Len(t, plugins, 0) + }) +} + +func TestGetInstalledMarketplacePlugins(t *testing.T) { + samplePlugins := []*model.MarketplacePlugin{ + { + BaseMarketplacePlugin: &model.BaseMarketplacePlugin{ + HomepageURL: "https://github.com/mattermost/mattermost-plugin-nps", + IconData: "http://example.com/icon.svg", + DownloadURL: "https://github.com/mattermost/mattermost-plugin-nps/releases/download/v1.0.3/com.mattermost.nps-1.0.3.tar.gz", + Manifest: &model.Manifest{ + Id: "com.mattermost.nps", + Name: "User Satisfaction Surveys", + Description: "This plugin sends quarterly user satisfaction surveys to gather feedback and help improve Mattermost.", + Version: "1.0.3", + MinServerVersion: "5.14.0", + }, + }, + InstalledVersion: "", + }, + } + + path, _ := fileutils.FindDir("tests") + tarData, err := ioutil.ReadFile(filepath.Join(path, "testplugin.tar.gz")) + require.NoError(t, err) + + t.Run("marketplace client returns not-installed plugin", func(t *testing.T) { + th := Setup().InitBasic() + defer th.TearDown() + + testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) { + res.WriteHeader(http.StatusOK) + json, err := json.Marshal(samplePlugins) + require.NoError(t, err) + res.Write(json) + })) + defer func() { testServer.Close() }() + + th.App.UpdateConfig(func(cfg *model.Config) { + *cfg.PluginSettings.Enable = true + *cfg.PluginSettings.EnableUploads = true + *cfg.PluginSettings.EnableMarketplace = true + *cfg.PluginSettings.MarketplaceUrl = testServer.URL + }) + + plugins, resp := th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{}) + CheckNoError(t, resp) + require.Equal(t, samplePlugins, plugins) + + manifest, resp := th.SystemAdminClient.UploadPlugin(bytes.NewReader(tarData)) + CheckNoError(t, resp) + + expectedPlugins := append(samplePlugins, &model.MarketplacePlugin{ + BaseMarketplacePlugin: &model.BaseMarketplacePlugin{ + HomepageURL: "", + IconData: "", + DownloadURL: "", + Manifest: manifest, + }, + InstalledVersion: manifest.Version, + }) + sort.SliceStable(expectedPlugins, func(i, j int) bool { + return strings.ToLower(expectedPlugins[i].Manifest.Name) < strings.ToLower(expectedPlugins[j].Manifest.Name) + }) + + plugins, resp = th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{}) + CheckNoError(t, resp) + require.Equal(t, expectedPlugins, plugins) + + ok, resp := th.SystemAdminClient.RemovePlugin(manifest.Id) + CheckNoError(t, resp) + assert.True(t, ok) + + plugins, resp = th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{}) + CheckNoError(t, resp) + require.Equal(t, samplePlugins, plugins) + }) + + t.Run("marketplace client returns installed plugin", func(t *testing.T) { + th := Setup().InitBasic() + defer th.TearDown() + + th.App.UpdateConfig(func(cfg *model.Config) { + *cfg.PluginSettings.Enable = true + *cfg.PluginSettings.EnableUploads = true + *cfg.PluginSettings.EnableMarketplace = true + }) + + manifest, resp := th.SystemAdminClient.UploadPlugin(bytes.NewReader(tarData)) + CheckNoError(t, resp) + + newPlugin := &model.MarketplacePlugin{ + BaseMarketplacePlugin: &model.BaseMarketplacePlugin{ + HomepageURL: "HomepageURL", + IconData: "IconData", + DownloadURL: "DownloadURL", + Manifest: manifest, + }, + InstalledVersion: manifest.Version, + } + expectedPlugins := append(samplePlugins, newPlugin) + sort.SliceStable(expectedPlugins, func(i, j int) bool { + return strings.ToLower(expectedPlugins[i].Manifest.Name) < strings.ToLower(expectedPlugins[j].Manifest.Name) + }) + + testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) { + res.WriteHeader(http.StatusOK) + json, err := json.Marshal([]*model.MarketplacePlugin{samplePlugins[0], newPlugin}) + require.NoError(t, err) + res.Write(json) + })) + defer func() { testServer.Close() }() + th.App.UpdateConfig(func(cfg *model.Config) { + *cfg.PluginSettings.MarketplaceUrl = testServer.URL + }) + + plugins, resp := th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{}) + CheckNoError(t, resp) + require.Equal(t, expectedPlugins, plugins) + + ok, resp := th.SystemAdminClient.RemovePlugin(manifest.Id) + CheckNoError(t, resp) + assert.True(t, ok) + + plugins, resp = th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{}) + CheckNoError(t, resp) + newPlugin.InstalledVersion = manifest.Version + require.Equal(t, expectedPlugins, plugins) + }) +} + +func TestSearchGetMarketplacePlugins(t *testing.T) { + samplePlugins := []*model.MarketplacePlugin{ + { + BaseMarketplacePlugin: &model.BaseMarketplacePlugin{ + HomepageURL: "https://github.com/mattermost/mattermost-plugin-nps", + IconData: "Cjxzdmcgdmlld0JveD0nMCAwIDEwNSA5MycgeG1sbnM9J2h0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnJz4KPHBhdGggZD0nTTY2LDBoMzl2OTN6TTM4LDBoLTM4djkzek01MiwzNWwyNSw1OGgtMTZsLTgtMThoLTE4eicgZmlsbD0nI0VEMUMyNCcvPgo8L3N2Zz4K", + DownloadURL: "https://github.com/mattermost/mattermost-plugin-nps/releases/download/v1.0.3/com.mattermost.nps-1.0.3.tar.gz", + Manifest: &model.Manifest{ + Id: "com.mattermost.nps", + Name: "User Satisfaction Surveys", + Description: "This plugin sends quarterly user satisfaction surveys to gather feedback and help improve Mattermost.", + Version: "1.0.3", + MinServerVersion: "5.14.0", + }, + }, + InstalledVersion: "", + }, + } + + path, _ := fileutils.FindDir("tests") + tarData, err := ioutil.ReadFile(filepath.Join(path, "testplugin.tar.gz")) + require.NoError(t, err) + + tarDataV2, err := ioutil.ReadFile(filepath.Join(path, "testpluginv2.tar.gz")) + require.NoError(t, err) + + t.Run("search installed plugin", func(t *testing.T) { + th := Setup().InitBasic() + defer th.TearDown() + + testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) { + res.WriteHeader(http.StatusOK) + json, err := json.Marshal(samplePlugins) + require.NoError(t, err) + res.Write(json) + })) + defer func() { testServer.Close() }() + + th.App.UpdateConfig(func(cfg *model.Config) { + *cfg.PluginSettings.Enable = true + *cfg.PluginSettings.EnableUploads = true + *cfg.PluginSettings.EnableMarketplace = true + *cfg.PluginSettings.MarketplaceUrl = testServer.URL + }) + + plugins, resp := th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{}) + CheckNoError(t, resp) + require.Equal(t, samplePlugins, plugins) + + manifest, resp := th.SystemAdminClient.UploadPlugin(bytes.NewReader(tarData)) + CheckNoError(t, resp) + + newPluginV1 := &model.MarketplacePlugin{ + BaseMarketplacePlugin: &model.BaseMarketplacePlugin{ + HomepageURL: "", + IconData: "", + DownloadURL: "", + Manifest: manifest, + }, + InstalledVersion: manifest.Version, + } + expectedPlugins := append(samplePlugins, newPluginV1) + + manifest, resp = th.SystemAdminClient.UploadPlugin(bytes.NewReader(tarDataV2)) + CheckNoError(t, resp) + newPluginV2 := &model.MarketplacePlugin{ + BaseMarketplacePlugin: &model.BaseMarketplacePlugin{ + HomepageURL: "", + IconData: "", + DownloadURL: "", + Manifest: manifest, + }, + InstalledVersion: manifest.Version, + } + expectedPlugins = append(expectedPlugins, newPluginV2) + sort.SliceStable(expectedPlugins, func(i, j int) bool { + return strings.ToLower(expectedPlugins[i].Manifest.Name) < strings.ToLower(expectedPlugins[j].Manifest.Name) + }) + + plugins, resp = th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{}) + CheckNoError(t, resp) + require.Equal(t, expectedPlugins, plugins) + + // Search for plugins from the server + plugins, resp = th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{Filter: "testplugin_v2"}) + CheckNoError(t, resp) + require.Equal(t, []*model.MarketplacePlugin{newPluginV2}, plugins) + + plugins, resp = th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{Filter: "dsgsdg_v2"}) + CheckNoError(t, resp) + require.Equal(t, []*model.MarketplacePlugin{newPluginV2}, plugins) + + plugins, resp = th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{Filter: "User Satisfaction Surveys"}) + CheckNoError(t, resp) + require.Equal(t, samplePlugins, plugins) + + plugins, resp = th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{Filter: "NOFILTER"}) + CheckNoError(t, resp) + require.Nil(t, plugins) + }) +} + func findClusterMessages(event string, msgs []*model.ClusterMessage) []*model.ClusterMessage { var result []*model.ClusterMessage for _, msg := range msgs { diff --git a/app/diagnostics.go b/app/diagnostics.go index 98a8f4dece..d5541b5814 100644 --- a/app/diagnostics.go +++ b/app/diagnostics.go @@ -602,6 +602,8 @@ func (a *App) trackConfig() { "enable_uploads": *cfg.PluginSettings.EnableUploads, "allow_insecure_download_url": *cfg.PluginSettings.AllowInsecureDownloadUrl, "enable_health_check": *cfg.PluginSettings.EnableHealthCheck, + "enable_marketplace": *cfg.PluginSettings.EnableMarketplace, + "is_default_marketplace_url": isDefault(*cfg.PluginSettings.MarketplaceUrl, model.PLUGIN_SETTINGS_DEFAULT_MARKETPLACE_URL), }) a.SendDiagnostic(TRACK_CONFIG_DATA_RETENTION, map[string]interface{}{ diff --git a/app/plugin.go b/app/plugin.go index 2a49a2ecb9..c1d67a44fc 100644 --- a/app/plugin.go +++ b/app/plugin.go @@ -7,12 +7,14 @@ import ( "net/http" "os" "path/filepath" + "sort" "strings" "github.com/mattermost/mattermost-server/mlog" "github.com/mattermost/mattermost-server/model" "github.com/mattermost/mattermost-server/plugin" "github.com/mattermost/mattermost-server/services/filesstore" + "github.com/mattermost/mattermost-server/services/marketplace" "github.com/mattermost/mattermost-server/utils/fileutils" "github.com/pkg/errors" ) @@ -400,6 +402,103 @@ func (a *App) GetPlugins() (*model.PluginsResponse, *model.AppError) { return resp, nil } +// GetMarketplacePlugins returns a list of plugins from the marketplace-server, +// and plugins that are installed locally. +func (a *App) GetMarketplacePlugins(filter *model.MarketplacePluginFilter) ([]*model.MarketplacePlugin, *model.AppError) { + var result []*model.MarketplacePlugin + pluginSet := map[string]bool{} + pluginsEnvironment := a.GetPluginsEnvironment() + if pluginsEnvironment == nil { + return nil, model.NewAppError("GetMarketplacePlugins", "app.plugin.config.app_error", nil, "", http.StatusInternalServerError) + } + + marketplaceClient, err := marketplace.NewClient( + *a.Config().PluginSettings.MarketplaceUrl, + a.HTTPService, + ) + if err != nil { + return nil, model.NewAppError("GetMarketplacePlugins", "app.plugin.marketplace_client.app_error", nil, err.Error(), http.StatusInternalServerError) + } + + // Fetch all plugins from marketplace. + marketplacePlugins, err := marketplaceClient.GetPlugins(&model.MarketplacePluginFilter{ + PerPage: -1, + ServerVersion: model.CurrentVersion, + }) + if err != nil { + return nil, model.NewAppError("GetMarketplacePlugins", "app.plugin.marketplace_plugins.app_error", nil, err.Error(), http.StatusInternalServerError) + } + + for _, p := range marketplacePlugins { + if p.Manifest == nil || !pluginMatchesFilter(p.Manifest, filter.Filter) { + continue + } + + marketplacePlugin := &model.MarketplacePlugin{ + BaseMarketplacePlugin: p, + } + + var manifest *model.Manifest + if manifest, err = pluginsEnvironment.GetManifest(p.Manifest.Id); err != nil && err != plugin.ErrNotFound { + return nil, model.NewAppError("GetMarketplacePlugins", "app.plugin.config.app_error", nil, err.Error(), http.StatusInternalServerError) + } else if err == nil { + // Plugin is installed. + marketplacePlugin.InstalledVersion = manifest.Version + } + + pluginSet[p.Manifest.Id] = true + result = append(result, marketplacePlugin) + } + + // Include all other installed plugins. + plugins, err := pluginsEnvironment.Available() + if err != nil { + return nil, model.NewAppError("GetMarketplacePlugins", "app.plugin.config.app_error", nil, err.Error(), http.StatusInternalServerError) + } + + for _, plugin := range plugins { + if plugin.Manifest == nil || pluginSet[plugin.Manifest.Id] || !pluginMatchesFilter(plugin.Manifest, filter.Filter) { + continue + } + + result = append(result, &model.MarketplacePlugin{ + BaseMarketplacePlugin: &model.BaseMarketplacePlugin{ + Manifest: plugin.Manifest, + }, + InstalledVersion: plugin.Manifest.Version, + }) + } + + // Sort result alphabetically. + sort.SliceStable(result, func(i, j int) bool { + return strings.ToLower(result[i].Manifest.Name) < strings.ToLower(result[j].Manifest.Name) + }) + + return result, nil +} + +func pluginMatchesFilter(manifest *model.Manifest, filter string) bool { + filter = strings.TrimSpace(strings.ToLower(filter)) + + if filter == "" { + return true + } + + if strings.ToLower(manifest.Id) == filter { + return true + } + + if strings.Contains(strings.ToLower(manifest.Name), filter) { + return true + } + + if strings.Contains(strings.ToLower(manifest.Description), filter) { + return true + } + + return false +} + // notifyPluginEnabled notifies connected websocket clients across all peers if the version of the given // plugin is same across them. // diff --git a/config/client.go b/config/client.go index a5a7a8c62c..3c1eca98cb 100644 --- a/config/client.go +++ b/config/client.go @@ -43,6 +43,7 @@ func GenerateClientConfig(c *model.Config, diagnosticId string, license *model.L props["ExperimentalEnableDefaultChannelLeaveJoinMessages"] = strconv.FormatBool(*c.ServiceSettings.ExperimentalEnableDefaultChannelLeaveJoinMessages) props["ExperimentalGroupUnreadChannels"] = *c.ServiceSettings.ExperimentalGroupUnreadChannels props["EnableSVGs"] = strconv.FormatBool(*c.ServiceSettings.EnableSVGs) + props["EnableMarketplace"] = strconv.FormatBool(*c.PluginSettings.EnableMarketplace) // This setting is only temporary, so keep using the old setting name for the mobile and web apps props["ExperimentalEnablePostMetadata"] = "true" diff --git a/i18n/en.json b/i18n/en.json index 2376e75418..778ce46cf3 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -3506,6 +3506,22 @@ "id": "app.plugin.manifest.app_error", "translation": "Unable to find manifest for extracted plugin" }, + { + "id": "app.plugin.marketplace_client.app_error", + "translation": "Failed to create marketplace client." + }, + { + "id": "app.plugin.marketplace_disabled.app_error", + "translation": "Marketplace has been disabled. Please check your logs for details." + }, + { + "id": "app.plugin.marketplace_plugins.app_error", + "translation": "Failed to get plugins from the marketplace server." + }, + { + "id": "app.plugin.marshal.app_error", + "translation": "Failed to marshal marketplace plugins." + }, { "id": "app.plugin.mvdir.app_error", "translation": "Unable to move plugin from temporary directory to final destination. Another plugin may be using the same directory name." diff --git a/model/client4.go b/model/client4.go index aac5fd4bf3..2dffa31291 100644 --- a/model/client4.go +++ b/model/client4.go @@ -4519,6 +4519,31 @@ func (c *Client4) DisablePlugin(id string) (bool, *Response) { return CheckStatusOK(r), BuildResponse(r) } +// GetMarketplacePlugins will return a list of plugins that an admin can install. +// WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE. +func (c *Client4) GetMarketplacePlugins(filter *MarketplacePluginFilter) ([]*MarketplacePlugin, *Response) { + route := c.GetPluginsRoute() + "/marketplace" + u, parseErr := url.Parse(route) + if parseErr != nil { + return nil, &Response{Error: NewAppError("GetMarketplacePlugins", "model.client.parse_plugins.app_error", nil, parseErr.Error(), http.StatusBadRequest)} + } + + filter.ApplyToURL(u) + + r, err := c.DoApiGet(u.String(), "") + if err != nil { + return nil, BuildErrorResponse(r, err) + } + defer closeBody(r) + + plugins, readerErr := MarketplacePluginsFromReader(r.Body) + if readerErr != nil { + return nil, BuildErrorResponse(r, NewAppError(route, "model.client.parse_plugins.app_error", nil, err.Error(), http.StatusBadRequest)) + } + + return plugins, BuildResponse(r) +} + // UpdateChannelScheme will update a channel's scheme. func (c *Client4) UpdateChannelScheme(channelId, schemeId string) (bool, *Response) { sip := &SchemeIDPatch{SchemeID: &schemeId} diff --git a/model/config.go b/model/config.go index 740c92ccf3..378933abc7 100644 --- a/model/config.go +++ b/model/config.go @@ -171,8 +171,10 @@ const ( DATA_RETENTION_SETTINGS_DEFAULT_FILE_RETENTION_DAYS = 365 DATA_RETENTION_SETTINGS_DEFAULT_DELETION_JOB_START_TIME = "02:00" - PLUGIN_SETTINGS_DEFAULT_DIRECTORY = "./plugins" - PLUGIN_SETTINGS_DEFAULT_CLIENT_DIRECTORY = "./client/plugins" + PLUGIN_SETTINGS_DEFAULT_DIRECTORY = "./plugins" + PLUGIN_SETTINGS_DEFAULT_CLIENT_DIRECTORY = "./client/plugins" + PLUGIN_SETTINGS_DEFAULT_ENABLE_MARKETPLACE = true + PLUGIN_SETTINGS_DEFAULT_MARKETPLACE_URL = "https://marketplace.integrations.mattermost.com" COMPLIANCE_EXPORT_TYPE_CSV = "csv" COMPLIANCE_EXPORT_TYPE_ACTIANCE = "actiance" @@ -2201,6 +2203,8 @@ type PluginSettings struct { ClientDirectory *string `restricted:"true"` Plugins map[string]map[string]interface{} PluginStates map[string]*PluginState + EnableMarketplace *bool + MarketplaceUrl *string } func (s *PluginSettings) SetDefaults(ls LogSettings) { @@ -2220,22 +2224,14 @@ func (s *PluginSettings) SetDefaults(ls LogSettings) { s.EnableHealthCheck = NewBool(true) } - if s.Directory == nil { + if s.Directory == nil || *s.Directory == "" { s.Directory = NewString(PLUGIN_SETTINGS_DEFAULT_DIRECTORY) } - if *s.Directory == "" { - *s.Directory = PLUGIN_SETTINGS_DEFAULT_DIRECTORY - } - - if s.ClientDirectory == nil { + if s.ClientDirectory == nil || *s.ClientDirectory == "" { s.ClientDirectory = NewString(PLUGIN_SETTINGS_DEFAULT_CLIENT_DIRECTORY) } - if *s.ClientDirectory == "" { - *s.ClientDirectory = PLUGIN_SETTINGS_DEFAULT_CLIENT_DIRECTORY - } - if s.Plugins == nil { s.Plugins = make(map[string]map[string]interface{}) } @@ -2248,6 +2244,14 @@ func (s *PluginSettings) SetDefaults(ls LogSettings) { // Enable the NPS plugin by default if diagnostics are enabled s.PluginStates["com.mattermost.nps"] = &PluginState{Enable: ls.EnableDiagnostics == nil || *ls.EnableDiagnostics} } + + if s.EnableMarketplace == nil { + s.EnableMarketplace = NewBool(PLUGIN_SETTINGS_DEFAULT_ENABLE_MARKETPLACE) + } + + if s.MarketplaceUrl == nil || *s.MarketplaceUrl == "" { + s.MarketplaceUrl = NewString(PLUGIN_SETTINGS_DEFAULT_MARKETPLACE_URL) + } } type GlobalRelayMessageExportSettings struct { diff --git a/model/marketplace_plugin.go b/model/marketplace_plugin.go new file mode 100644 index 0000000000..154bdde00d --- /dev/null +++ b/model/marketplace_plugin.go @@ -0,0 +1,69 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +package model + +import ( + "encoding/json" + "io" + "net/url" + "strconv" +) + +// BaseMarketplacePlugin is a Mattermost plugin received from the marketplace server. +type BaseMarketplacePlugin struct { + HomepageURL string `json:"homepage_url"` + DownloadURL string `json:"download_url"` + IconData string `json:"icon_data"` + Manifest *Manifest `json:"manifest"` +} + +// MarketplacePlugin is a state aware marketplace plugin. +type MarketplacePlugin struct { + *BaseMarketplacePlugin + InstalledVersion string `json:"installed_version"` +} + +// BaseMarketplacePluginsFromReader decodes a json-encoded list of plugins from the given io.Reader. +func BaseMarketplacePluginsFromReader(reader io.Reader) ([]*BaseMarketplacePlugin, error) { + plugins := []*BaseMarketplacePlugin{} + decoder := json.NewDecoder(reader) + + if err := decoder.Decode(&plugins); err != nil && err != io.EOF { + return nil, err + } + + return plugins, nil +} + +// MarketplacePluginsFromReader decodes a json-encoded list of plugins from the given io.Reader. +func MarketplacePluginsFromReader(reader io.Reader) ([]*MarketplacePlugin, error) { + plugins := []*MarketplacePlugin{} + decoder := json.NewDecoder(reader) + + if err := decoder.Decode(&plugins); err != nil && err != io.EOF { + return nil, err + } + + return plugins, nil +} + +// MarketplacePluginFilter describes the parameters to request a list of plugins. +type MarketplacePluginFilter struct { + Page int + PerPage int + Filter string + ServerVersion string +} + +// ApplyToURL modifies the given url to include query string parameters for the request. +func (filter *MarketplacePluginFilter) ApplyToURL(u *url.URL) { + q := u.Query() + q.Add("page", strconv.Itoa(filter.Page)) + if filter.PerPage > 0 { + q.Add("per_page", strconv.Itoa(filter.PerPage)) + } + q.Add("filter", filter.Filter) + q.Add("server_version", filter.ServerVersion) + u.RawQuery = q.Encode() +} diff --git a/plugin/environment.go b/plugin/environment.go index e4410cf26a..3a9cdf7ab0 100644 --- a/plugin/environment.go +++ b/plugin/environment.go @@ -18,6 +18,8 @@ import ( "github.com/pkg/errors" ) +var ErrNotFound = errors.New("Item not found") + type apiImplCreatorFunc func(*model.Manifest) API // registeredPlugin stores the state for a given plugin that has been activated @@ -162,6 +164,23 @@ func (env *Environment) Statuses() (model.PluginStatuses, error) { return pluginStatuses, nil } +// GetManifest returns a manifest for a given pluginId. +// Returns ErrNotFound if plugin is not found. +func (env *Environment) GetManifest(pluginId string) (*model.Manifest, error) { + plugins, err := env.Available() + if err != nil { + return nil, errors.Wrap(err, "unable to get plugin statuses") + } + + for _, plugin := range plugins { + if plugin.Manifest != nil && plugin.Manifest.Id == pluginId { + return plugin.Manifest, nil + } + } + + return nil, ErrNotFound +} + func (env *Environment) Activate(id string) (manifest *model.Manifest, activated bool, reterr error) { // Check if we are already active if env.IsActive(id) { diff --git a/services/marketplace/client.go b/services/marketplace/client.go new file mode 100644 index 0000000000..9b03dd8c50 --- /dev/null +++ b/services/marketplace/client.go @@ -0,0 +1,79 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package marketplace + +import ( + "fmt" + "io/ioutil" + "net/http" + "net/url" + + "github.com/mattermost/mattermost-server/model" + "github.com/mattermost/mattermost-server/services/httpservice" + "github.com/pkg/errors" +) + +// Client is the programmatic interface to the marketplace server API. +type Client struct { + address string + httpClient *http.Client +} + +// NewClient creates a client to the marketplace server at the given address. +func NewClient(address string, httpService httpservice.HTTPService) (*Client, error) { + var httpClient *http.Client + addressUrl, err := url.Parse(address) + if err != nil { + return nil, errors.Wrap(err, "failed to parse marketplace address") + } + if addressUrl.Hostname() == "localhost" || addressUrl.Hostname() == "127.0.0.1" { + httpClient = httpService.MakeClient(true) + } else { + httpClient = httpService.MakeClient(false) + } + + return &Client{ + address: address, + httpClient: httpClient, + }, nil +} + +// GetPlugins fetches the list of plugins from the configured server. +func (c *Client) GetPlugins(request *model.MarketplacePluginFilter) ([]*model.BaseMarketplacePlugin, error) { + u, err := url.Parse(c.buildURL("/api/v1/plugins")) + if err != nil { + return nil, err + } + + request.ApplyToURL(u) + + resp, err := c.doGet(u.String()) + if err != nil { + return nil, err + } + defer closeBody(resp) + + switch resp.StatusCode { + case http.StatusOK: + return model.BaseMarketplacePluginsFromReader(resp.Body) + default: + return nil, errors.Errorf("failed with status code %d", resp.StatusCode) + } +} + +// closeBody ensures the Body of an http.Response is properly closed. +func closeBody(r *http.Response) { + if r.Body != nil { + _, _ = ioutil.ReadAll(r.Body) + _ = r.Body.Close() + } +} + +func (c *Client) buildURL(urlPath string, args ...interface{}) string { + return fmt.Sprintf("%s%s", c.address, fmt.Sprintf(urlPath, args...)) +} + +func (c *Client) doGet(u string) (*http.Response, error) { + return c.httpClient.Get(u) +} diff --git a/tests/testpluginv2.tar.gz b/tests/testpluginv2.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..1e0693fb51a5147f785f95aee2c1c86f29fd4e94 GIT binary patch literal 71989 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 literal 0 HcmV?d00001