From daebd26a2894d88eb4c703b3be75f042cd563fef Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 30 Nov 2017 14:55:44 -0600 Subject: PLT-8018: Bundled jira plugin (#7920) * bundled jira plugin * fix generated file formatting, add prepackaged key * whoops, uploaded wrong file * whitelist generated files for license check * make it work for people without go/bin in their path --- app/plugin.go | 98 +++++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 68 insertions(+), 30 deletions(-) (limited to 'app/plugin.go') diff --git a/app/plugin.go b/app/plugin.go index 4645eb9fb..6421e19a6 100644 --- a/app/plugin.go +++ b/app/plugin.go @@ -4,6 +4,7 @@ package app import ( + "bytes" "context" "io" "io/ioutil" @@ -26,9 +27,12 @@ import ( "github.com/mattermost/mattermost-server/plugin/pluginenv" ) +var prepackagedPlugins map[string]func(string) ([]byte, error) = map[string]func(string) ([]byte, error){ + "jira": jira.Asset, +} + func (a *App) initBuiltInPlugins() { plugins := map[string]builtinplugin.Plugin{ - "jira": &jira.Plugin{}, "ldapextras": &ldapextras.Plugin{}, } for id, p := range plugins { @@ -106,24 +110,28 @@ func (a *App) ActivatePlugins() { // InstallPlugin unpacks and installs a plugin but does not activate it. func (a *App) InstallPlugin(pluginFile io.Reader) (*model.Manifest, *model.AppError) { + return a.installPlugin(pluginFile, false) +} + +func (a *App) installPlugin(pluginFile io.Reader, allowPrepackaged bool) (*model.Manifest, *model.AppError) { if a.PluginEnv == nil || !*a.Config().PluginSettings.Enable { - return nil, model.NewAppError("InstallPlugin", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented) + return nil, model.NewAppError("installPlugin", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented) } tmpDir, err := ioutil.TempDir("", "plugintmp") if err != nil { - return nil, model.NewAppError("InstallPlugin", "app.plugin.filesystem.app_error", nil, err.Error(), http.StatusInternalServerError) + return nil, model.NewAppError("installPlugin", "app.plugin.filesystem.app_error", nil, err.Error(), http.StatusInternalServerError) } defer os.RemoveAll(tmpDir) if err := utils.ExtractTarGz(pluginFile, tmpDir); err != nil { - return nil, model.NewAppError("InstallPlugin", "app.plugin.extract.app_error", nil, err.Error(), http.StatusBadRequest) + return nil, model.NewAppError("installPlugin", "app.plugin.extract.app_error", nil, err.Error(), http.StatusBadRequest) } tmpPluginDir := tmpDir dir, err := ioutil.ReadDir(tmpDir) if err != nil { - return nil, model.NewAppError("InstallPlugin", "app.plugin.filesystem.app_error", nil, err.Error(), http.StatusInternalServerError) + return nil, model.NewAppError("installPlugin", "app.plugin.filesystem.app_error", nil, err.Error(), http.StatusInternalServerError) } if len(dir) == 1 && dir[0].IsDir() { @@ -132,23 +140,27 @@ func (a *App) InstallPlugin(pluginFile io.Reader) (*model.Manifest, *model.AppEr manifest, _, err := model.FindManifest(tmpPluginDir) if err != nil { - return nil, model.NewAppError("InstallPlugin", "app.plugin.manifest.app_error", nil, err.Error(), http.StatusBadRequest) + return nil, model.NewAppError("installPlugin", "app.plugin.manifest.app_error", nil, err.Error(), http.StatusBadRequest) + } + + if _, ok := prepackagedPlugins[manifest.Id]; ok && !allowPrepackaged { + return nil, model.NewAppError("installPlugin", "app.plugin.prepackaged.app_error", nil, "", http.StatusBadRequest) } bundles, err := a.PluginEnv.Plugins() if err != nil { - return nil, model.NewAppError("InstallPlugin", "app.plugin.install.app_error", nil, err.Error(), http.StatusInternalServerError) + return nil, model.NewAppError("installPlugin", "app.plugin.install.app_error", nil, err.Error(), http.StatusInternalServerError) } for _, bundle := range bundles { if bundle.Manifest.Id == manifest.Id { - return nil, model.NewAppError("InstallPlugin", "app.plugin.install_id.app_error", nil, "", http.StatusBadRequest) + return nil, model.NewAppError("installPlugin", "app.plugin.install_id.app_error", nil, "", http.StatusBadRequest) } } err = utils.CopyDir(tmpPluginDir, filepath.Join(a.PluginEnv.SearchPath(), manifest.Id)) if err != nil { - return nil, model.NewAppError("InstallPlugin", "app.plugin.mvdir.app_error", nil, err.Error(), http.StatusInternalServerError) + return nil, model.NewAppError("installPlugin", "app.plugin.mvdir.app_error", nil, err.Error(), http.StatusInternalServerError) } // Should add manifest validation and error handling here @@ -156,22 +168,26 @@ func (a *App) InstallPlugin(pluginFile io.Reader) (*model.Manifest, *model.AppEr return manifest, nil } -func (a *App) GetPluginManifests() (*model.PluginsResponse, *model.AppError) { +func (a *App) GetPlugins() (*model.PluginsResponse, *model.AppError) { if a.PluginEnv == nil || !*a.Config().PluginSettings.Enable { - return nil, model.NewAppError("GetPluginManifests", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented) + return nil, model.NewAppError("GetPlugins", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented) } plugins, err := a.PluginEnv.Plugins() if err != nil { - return nil, model.NewAppError("GetPluginManifests", "app.plugin.get_plugins.app_error", nil, err.Error(), http.StatusInternalServerError) + return nil, model.NewAppError("GetPlugins", "app.plugin.get_plugins.app_error", nil, err.Error(), http.StatusInternalServerError) } - resp := &model.PluginsResponse{Active: []*model.Manifest{}, Inactive: []*model.Manifest{}} + resp := &model.PluginsResponse{Active: []*model.PluginInfo{}, Inactive: []*model.PluginInfo{}} for _, plugin := range plugins { + info := &model.PluginInfo{ + Manifest: *plugin.Manifest, + } + _, info.Prepackaged = prepackagedPlugins[plugin.Manifest.Id] if a.PluginEnv.IsPluginActive(plugin.Manifest.Id) { - resp.Active = append(resp.Active, plugin.Manifest) + resp.Active = append(resp.Active, info) } else { - resp.Inactive = append(resp.Inactive, plugin.Manifest) + resp.Inactive = append(resp.Inactive, info) } } @@ -194,13 +210,21 @@ func (a *App) GetActivePluginManifests() ([]*model.Manifest, *model.AppError) { } func (a *App) RemovePlugin(id string) *model.AppError { + return a.removePlugin(id, false) +} + +func (a *App) removePlugin(id string, allowPrepackaged bool) *model.AppError { if a.PluginEnv == nil || !*a.Config().PluginSettings.Enable { - return model.NewAppError("RemovePlugin", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented) + return model.NewAppError("removePlugin", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented) + } + + if _, ok := prepackagedPlugins[id]; ok && !allowPrepackaged { + return model.NewAppError("removePlugin", "app.plugin.prepackaged.app_error", nil, "", http.StatusBadRequest) } plugins, err := a.PluginEnv.Plugins() if err != nil { - return model.NewAppError("RemovePlugin", "app.plugin.deactivate.app_error", nil, err.Error(), http.StatusBadRequest) + return model.NewAppError("removePlugin", "app.plugin.deactivate.app_error", nil, err.Error(), http.StatusBadRequest) } var manifest *model.Manifest @@ -212,13 +236,13 @@ func (a *App) RemovePlugin(id string) *model.AppError { } if manifest == nil { - return model.NewAppError("RemovePlugin", "app.plugin.not_installed.app_error", nil, "", http.StatusBadRequest) + return model.NewAppError("removePlugin", "app.plugin.not_installed.app_error", nil, "", http.StatusBadRequest) } if a.PluginEnv.IsPluginActive(id) { err := a.PluginEnv.DeactivatePlugin(id) if err != nil { - return model.NewAppError("RemovePlugin", "app.plugin.deactivate.app_error", nil, err.Error(), http.StatusBadRequest) + return model.NewAppError("removePlugin", "app.plugin.deactivate.app_error", nil, err.Error(), http.StatusBadRequest) } if manifest.HasClient() { @@ -230,7 +254,7 @@ func (a *App) RemovePlugin(id string) *model.AppError { err = os.RemoveAll(filepath.Join(a.PluginEnv.SearchPath(), id)) if err != nil { - return model.NewAppError("RemovePlugin", "app.plugin.remove.app_error", nil, err.Error(), http.StatusInternalServerError) + return model.NewAppError("removePlugin", "app.plugin.remove.app_error", nil, err.Error(), http.StatusInternalServerError) } return nil @@ -239,7 +263,7 @@ func (a *App) RemovePlugin(id string) *model.AppError { // EnablePlugin will set the config for an installed plugin to enabled, triggering activation if inactive. func (a *App) EnablePlugin(id string) *model.AppError { if a.PluginEnv == nil || !*a.Config().PluginSettings.Enable { - return model.NewAppError("RemovePlugin", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented) + return model.NewAppError("EnablePlugin", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented) } plugins, err := a.PluginEnv.Plugins() @@ -273,7 +297,7 @@ func (a *App) EnablePlugin(id string) *model.AppError { // DisablePlugin will set the config for an installed plugin to disabled, triggering deactivation if active. func (a *App) DisablePlugin(id string) *model.AppError { if a.PluginEnv == nil || !*a.Config().PluginSettings.Enable { - return model.NewAppError("RemovePlugin", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented) + return model.NewAppError("DisablePlugin", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented) } plugins, err := a.PluginEnv.Plugins() @@ -315,19 +339,17 @@ func (a *App) InitPlugins(pluginPath, webappPath string) { l4g.Info("Starting up plugins") - err := os.Mkdir(pluginPath, 0744) - if err != nil && !os.IsExist(err) { + if err := os.Mkdir(pluginPath, 0744); err != nil && !os.IsExist(err) { l4g.Error("failed to start up plugins: " + err.Error()) return } - err = os.Mkdir(webappPath, 0744) - if err != nil && !os.IsExist(err) { + if err := os.Mkdir(webappPath, 0744); err != nil && !os.IsExist(err) { l4g.Error("failed to start up plugins: " + err.Error()) return } - a.PluginEnv, err = pluginenv.New( + if env, err := pluginenv.New( pluginenv.SearchPath(pluginPath), pluginenv.WebappPath(webappPath), pluginenv.APIProvider(func(m *model.Manifest) (plugin.API, error) { @@ -340,11 +362,27 @@ func (a *App) InitPlugins(pluginPath, webappPath string) { }, }, nil }), - ) - - if err != nil { + ); err != nil { l4g.Error("failed to start up plugins: " + err.Error()) return + } else { + a.PluginEnv = env + } + + for id, asset := range prepackagedPlugins { + if tarball, err := asset("plugin.tar.gz"); err != nil { + l4g.Error("failed to install prepackaged plugin: " + err.Error()) + } else if tarball != nil { + a.removePlugin(id, true) + if _, err := a.installPlugin(bytes.NewReader(tarball), true); err != nil { + l4g.Error("failed to install prepackaged plugin: " + err.Error()) + } + if _, ok := a.Config().PluginSettings.PluginStates[id]; !ok { + if err := a.EnablePlugin(id); err != nil { + l4g.Error("failed to enable prepackaged plugin: " + err.Error()) + } + } + } } utils.RemoveConfigListener(a.PluginConfigListenerId) -- cgit v1.2.3-1-g7c22