mirror of
https://github.com/mattermost/mattermost.git
synced 2025-02-25 18:55:24 -06:00
Differentiate between installed and activated states for plugins (#7706)
This commit is contained in:
@@ -24,6 +24,9 @@ func (api *API) InitPlugin() {
|
||||
api.BaseRoutes.Plugins.Handle("", api.ApiSessionRequired(getPlugins)).Methods("GET")
|
||||
api.BaseRoutes.Plugin.Handle("", api.ApiSessionRequired(removePlugin)).Methods("DELETE")
|
||||
|
||||
api.BaseRoutes.Plugin.Handle("/activate", api.ApiSessionRequired(activatePlugin)).Methods("POST")
|
||||
api.BaseRoutes.Plugin.Handle("/deactivate", api.ApiSessionRequired(deactivatePlugin)).Methods("POST")
|
||||
|
||||
api.BaseRoutes.Plugins.Handle("/webapp", api.ApiHandler(getWebappPlugins)).Methods("GET")
|
||||
|
||||
}
|
||||
@@ -64,7 +67,7 @@ func uploadPlugin(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
manifest, unpackErr := c.App.UnpackAndActivatePlugin(file)
|
||||
manifest, unpackErr := c.App.InstallPlugin(file)
|
||||
|
||||
if unpackErr != nil {
|
||||
c.Err = unpackErr
|
||||
@@ -86,13 +89,13 @@ func getPlugins(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
manifests, err := c.App.GetActivePluginManifests()
|
||||
response, err := c.App.GetPluginManifests()
|
||||
if err != nil {
|
||||
c.Err = err
|
||||
return
|
||||
}
|
||||
|
||||
w.Write([]byte(model.ManifestListToJson(manifests)))
|
||||
w.Write([]byte(response.ToJson()))
|
||||
}
|
||||
|
||||
func removePlugin(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
@@ -141,3 +144,51 @@ 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) {
|
||||
c.RequirePluginId()
|
||||
if c.Err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if !*c.App.Config().PluginSettings.Enable {
|
||||
c.Err = model.NewAppError("activatePlugin", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented)
|
||||
return
|
||||
}
|
||||
|
||||
if !app.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) {
|
||||
c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM)
|
||||
return
|
||||
}
|
||||
|
||||
if err := c.App.EnablePlugin(c.Params.PluginId); err != nil {
|
||||
c.Err = err
|
||||
return
|
||||
}
|
||||
|
||||
ReturnStatusOK(w)
|
||||
}
|
||||
|
||||
func deactivatePlugin(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
c.RequirePluginId()
|
||||
if c.Err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if !*c.App.Config().PluginSettings.Enable {
|
||||
c.Err = model.NewAppError("deactivatePlugin", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented)
|
||||
return
|
||||
}
|
||||
|
||||
if !app.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) {
|
||||
c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM)
|
||||
return
|
||||
}
|
||||
|
||||
if err := c.App.DisablePlugin(c.Params.PluginId); err != nil {
|
||||
c.Err = err
|
||||
return
|
||||
}
|
||||
|
||||
ReturnStatusOK(w)
|
||||
}
|
||||
|
||||
@@ -65,12 +65,12 @@ func TestPlugin(t *testing.T) {
|
||||
_, resp = th.Client.UploadPlugin(file)
|
||||
CheckForbiddenStatus(t, resp)
|
||||
|
||||
// Successful get
|
||||
manifests, resp := th.SystemAdminClient.GetPlugins()
|
||||
// Successful gets
|
||||
pluginsResp, resp := th.SystemAdminClient.GetPlugins()
|
||||
CheckNoError(t, resp)
|
||||
|
||||
found := false
|
||||
for _, m := range manifests {
|
||||
for _, m := range pluginsResp.Inactive {
|
||||
if m.Id == manifest.Id {
|
||||
found = true
|
||||
}
|
||||
@@ -78,6 +78,64 @@ func TestPlugin(t *testing.T) {
|
||||
|
||||
assert.True(t, found)
|
||||
|
||||
found = false
|
||||
for _, m := range pluginsResp.Active {
|
||||
if m.Id == manifest.Id {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
|
||||
assert.False(t, found)
|
||||
|
||||
states := th.App.Config().PluginSettings.PluginStates
|
||||
defer func() {
|
||||
th.App.UpdateConfig(func(cfg *model.Config) { cfg.PluginSettings.PluginStates = states })
|
||||
}()
|
||||
|
||||
// Successful activate
|
||||
ok, resp := th.SystemAdminClient.ActivatePlugin(manifest.Id)
|
||||
CheckNoError(t, resp)
|
||||
assert.True(t, ok)
|
||||
|
||||
pluginsResp, resp = th.SystemAdminClient.GetPlugins()
|
||||
CheckNoError(t, resp)
|
||||
|
||||
found = false
|
||||
for _, m := range pluginsResp.Active {
|
||||
if m.Id == manifest.Id {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
|
||||
assert.True(t, found)
|
||||
|
||||
// Activate error case
|
||||
ok, resp = th.SystemAdminClient.ActivatePlugin("junk")
|
||||
CheckBadRequestStatus(t, resp)
|
||||
assert.False(t, ok)
|
||||
|
||||
// Successful deactivate
|
||||
ok, resp = th.SystemAdminClient.DeactivatePlugin(manifest.Id)
|
||||
CheckNoError(t, resp)
|
||||
assert.True(t, ok)
|
||||
|
||||
pluginsResp, resp = th.SystemAdminClient.GetPlugins()
|
||||
CheckNoError(t, resp)
|
||||
|
||||
found = false
|
||||
for _, m := range pluginsResp.Inactive {
|
||||
if m.Id == manifest.Id {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
|
||||
assert.True(t, found)
|
||||
|
||||
// Deactivate error case
|
||||
ok, resp = th.SystemAdminClient.DeactivatePlugin("junk")
|
||||
CheckBadRequestStatus(t, resp)
|
||||
assert.False(t, ok)
|
||||
|
||||
// Get error cases
|
||||
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.PluginSettings.Enable = false })
|
||||
_, resp = th.SystemAdminClient.GetPlugins()
|
||||
@@ -88,7 +146,10 @@ func TestPlugin(t *testing.T) {
|
||||
CheckForbiddenStatus(t, resp)
|
||||
|
||||
// Successful webapp get
|
||||
manifests, resp = th.Client.GetWebappPlugins()
|
||||
_, resp = th.SystemAdminClient.ActivatePlugin(manifest.Id)
|
||||
CheckNoError(t, resp)
|
||||
|
||||
manifests, resp := th.Client.GetWebappPlugins()
|
||||
CheckNoError(t, resp)
|
||||
|
||||
found = false
|
||||
@@ -101,15 +162,13 @@ func TestPlugin(t *testing.T) {
|
||||
assert.True(t, found)
|
||||
|
||||
// Successful remove
|
||||
ok, resp := th.SystemAdminClient.RemovePlugin(manifest.Id)
|
||||
ok, resp = th.SystemAdminClient.RemovePlugin(manifest.Id)
|
||||
CheckNoError(t, resp)
|
||||
|
||||
assert.True(t, ok)
|
||||
|
||||
// Remove error cases
|
||||
ok, resp = th.SystemAdminClient.RemovePlugin(manifest.Id)
|
||||
CheckBadRequestStatus(t, resp)
|
||||
|
||||
assert.False(t, ok)
|
||||
|
||||
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.PluginSettings.Enable = false })
|
||||
|
||||
188
app/plugins.go
188
app/plugins.go
@@ -273,6 +273,8 @@ func (a *App) InitBuiltInPlugins() {
|
||||
}
|
||||
}
|
||||
|
||||
// ActivatePlugins will activate any plugins enabled in the config
|
||||
// and deactivate all other plugins.
|
||||
func (a *App) ActivatePlugins() {
|
||||
if a.PluginEnv == nil {
|
||||
l4g.Error("plugin env not initialized")
|
||||
@@ -281,20 +283,52 @@ func (a *App) ActivatePlugins() {
|
||||
|
||||
plugins, err := a.PluginEnv.Plugins()
|
||||
if err != nil {
|
||||
l4g.Error("failed to start up plugins: " + err.Error())
|
||||
l4g.Error("failed to activate plugins: " + err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
for _, plugin := range plugins {
|
||||
err := a.PluginEnv.ActivatePlugin(plugin.Manifest.Id)
|
||||
if err != nil {
|
||||
l4g.Error(err.Error())
|
||||
id := plugin.Manifest.Id
|
||||
|
||||
pluginState := &model.PluginState{Enable: false}
|
||||
if state, ok := a.Config().PluginSettings.PluginStates[id]; ok {
|
||||
pluginState = state
|
||||
}
|
||||
|
||||
active := a.PluginEnv.IsPluginActive(id)
|
||||
|
||||
if pluginState.Enable && !active {
|
||||
if err := a.PluginEnv.ActivatePlugin(id); err != nil {
|
||||
l4g.Error(err.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
if plugin.Manifest.HasClient() {
|
||||
message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_PLUGIN_ACTIVATED, "", "", "", nil)
|
||||
message.Add("manifest", plugin.Manifest.ClientManifest())
|
||||
a.Publish(message)
|
||||
}
|
||||
|
||||
l4g.Info("Activated %v plugin", id)
|
||||
} else if !pluginState.Enable && active {
|
||||
if err := a.PluginEnv.DeactivatePlugin(id); err != nil {
|
||||
l4g.Error(err.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
if plugin.Manifest.HasClient() {
|
||||
message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_PLUGIN_DEACTIVATED, "", "", "", nil)
|
||||
message.Add("manifest", plugin.Manifest.ClientManifest())
|
||||
a.Publish(message)
|
||||
}
|
||||
|
||||
l4g.Info("Deactivated %v plugin", id)
|
||||
}
|
||||
l4g.Info("Activated %v plugin", plugin.Manifest.Id)
|
||||
}
|
||||
}
|
||||
|
||||
func (a *App) UnpackAndActivatePlugin(pluginFile io.Reader) (*model.Manifest, *model.AppError) {
|
||||
// InstallPlugin unpacks and installs a plugin but does not activate it.
|
||||
func (a *App) InstallPlugin(pluginFile io.Reader) (*model.Manifest, *model.AppError) {
|
||||
if a.PluginEnv == nil || !*a.Config().PluginSettings.Enable {
|
||||
return nil, model.NewAppError("UnpackAndActivatePlugin", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented)
|
||||
}
|
||||
@@ -331,20 +365,31 @@ func (a *App) UnpackAndActivatePlugin(pluginFile io.Reader) (*model.Manifest, *m
|
||||
|
||||
// Should add manifest validation and error handling here
|
||||
|
||||
err = a.PluginEnv.ActivatePlugin(manifest.Id)
|
||||
if err != nil {
|
||||
return nil, model.NewAppError("UnpackAndActivatePlugin", "app.plugin.activate.app_error", nil, err.Error(), http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if manifest.HasClient() {
|
||||
message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_PLUGIN_ACTIVATED, "", "", "", nil)
|
||||
message.Add("manifest", manifest.ClientManifest())
|
||||
a.Publish(message)
|
||||
}
|
||||
|
||||
return manifest, nil
|
||||
}
|
||||
|
||||
func (a *App) GetPluginManifests() (*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)
|
||||
}
|
||||
|
||||
plugins, err := a.PluginEnv.Plugins()
|
||||
if err != nil {
|
||||
return nil, model.NewAppError("GetPluginManifests", "app.plugin.get_plugins.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
resp := &model.PluginsResponse{Active: []*model.Manifest{}, Inactive: []*model.Manifest{}}
|
||||
for _, plugin := range plugins {
|
||||
if a.PluginEnv.IsPluginActive(plugin.Manifest.Id) {
|
||||
resp.Active = append(resp.Active, plugin.Manifest)
|
||||
} else {
|
||||
resp.Inactive = append(resp.Inactive, plugin.Manifest)
|
||||
}
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (a *App) GetActivePluginManifests() ([]*model.Manifest, *model.AppError) {
|
||||
if a.PluginEnv == nil || !*a.Config().PluginSettings.Enable {
|
||||
return nil, model.NewAppError("GetActivePluginManifests", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented)
|
||||
@@ -365,8 +410,12 @@ func (a *App) RemovePlugin(id string) *model.AppError {
|
||||
return model.NewAppError("RemovePlugin", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
plugins := a.PluginEnv.ActivePlugins()
|
||||
manifest := &model.Manifest{}
|
||||
plugins, err := a.PluginEnv.Plugins()
|
||||
if err != nil {
|
||||
return model.NewAppError("RemovePlugin", "app.plugin.deactivate.app_error", nil, err.Error(), http.StatusBadRequest)
|
||||
}
|
||||
|
||||
var manifest *model.Manifest
|
||||
for _, p := range plugins {
|
||||
if p.Manifest.Id == id {
|
||||
manifest = p.Manifest
|
||||
@@ -374,9 +423,21 @@ func (a *App) RemovePlugin(id string) *model.AppError {
|
||||
}
|
||||
}
|
||||
|
||||
err := a.PluginEnv.DeactivatePlugin(id)
|
||||
if err != nil {
|
||||
return model.NewAppError("RemovePlugin", "app.plugin.deactivate.app_error", nil, err.Error(), http.StatusBadRequest)
|
||||
if manifest == nil {
|
||||
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)
|
||||
}
|
||||
|
||||
if manifest.HasClient() {
|
||||
message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_PLUGIN_DEACTIVATED, "", "", "", nil)
|
||||
message.Add("manifest", manifest.ClientManifest())
|
||||
a.Publish(message)
|
||||
}
|
||||
}
|
||||
|
||||
err = os.RemoveAll(filepath.Join(a.PluginEnv.SearchPath(), id))
|
||||
@@ -384,10 +445,70 @@ func (a *App) RemovePlugin(id string) *model.AppError {
|
||||
return model.NewAppError("RemovePlugin", "app.plugin.remove.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
if manifest.HasClient() {
|
||||
message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_PLUGIN_DEACTIVATED, "", "", "", nil)
|
||||
message.Add("manifest", manifest.ClientManifest())
|
||||
a.Publish(message)
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
plugins, err := a.PluginEnv.Plugins()
|
||||
if err != nil {
|
||||
return model.NewAppError("EnablePlugin", "app.plugin.config.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
var manifest *model.Manifest
|
||||
for _, p := range plugins {
|
||||
if p.Manifest.Id == id {
|
||||
manifest = p.Manifest
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if manifest == nil {
|
||||
return model.NewAppError("EnablePlugin", "app.plugin.not_installed.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
cfg := a.Config()
|
||||
cfg.PluginSettings.PluginStates[id] = &model.PluginState{Enable: true}
|
||||
|
||||
if err := a.SaveConfig(cfg, true); err != nil {
|
||||
return model.NewAppError("EnablePlugin", "app.plugin.config.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
plugins, err := a.PluginEnv.Plugins()
|
||||
if err != nil {
|
||||
return model.NewAppError("DisablePlugin", "app.plugin.config.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
var manifest *model.Manifest
|
||||
for _, p := range plugins {
|
||||
if p.Manifest.Id == id {
|
||||
manifest = p.Manifest
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if manifest == nil {
|
||||
return model.NewAppError("DisablePlugin", "app.plugin.not_installed.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
cfg := a.Config()
|
||||
cfg.PluginSettings.PluginStates[id] = &model.PluginState{Enable: false}
|
||||
|
||||
if err := a.SaveConfig(cfg, true); err != nil {
|
||||
return model.NewAppError("DisablePlugin", "app.plugin.config.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -432,7 +553,20 @@ func (a *App) InitPlugins(pluginPath, webappPath string) {
|
||||
return
|
||||
}
|
||||
|
||||
a.PluginConfigListenerId = utils.AddConfigListener(func(_, _ *model.Config) {
|
||||
utils.RemoveConfigListener(a.PluginConfigListenerId)
|
||||
a.PluginConfigListenerId = utils.AddConfigListener(func(prevCfg, cfg *model.Config) {
|
||||
if !*prevCfg.PluginSettings.Enable && *cfg.PluginSettings.Enable {
|
||||
a.InitPlugins(pluginPath, webappPath)
|
||||
} else if *prevCfg.PluginSettings.Enable && !*cfg.PluginSettings.Enable {
|
||||
a.ShutDownPlugins()
|
||||
} else if *prevCfg.PluginSettings.Enable && *cfg.PluginSettings.Enable {
|
||||
a.ActivatePlugins()
|
||||
}
|
||||
|
||||
if a.PluginEnv == nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, err := range a.PluginEnv.Hooks().OnConfigurationChange() {
|
||||
l4g.Error(err.Error())
|
||||
}
|
||||
|
||||
@@ -75,14 +75,6 @@ func runServer(configFileLocation string) {
|
||||
|
||||
if webappDir, ok := utils.FindDir(model.CLIENT_DIR); ok {
|
||||
a.InitPlugins("plugins", webappDir+"/plugins")
|
||||
|
||||
utils.AddConfigListener(func(prevCfg *model.Config, cfg *model.Config) {
|
||||
if !*prevCfg.PluginSettings.Enable && *cfg.PluginSettings.Enable {
|
||||
a.InitPlugins("plugins", webappDir+"/plugins")
|
||||
} else if *prevCfg.PluginSettings.Enable && !*cfg.PluginSettings.Enable {
|
||||
a.ShutDownPlugins()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
l4g.Error("Unable to find webapp directory, could not initialize plugins")
|
||||
}
|
||||
|
||||
12
i18n/en.json
12
i18n/en.json
@@ -3471,6 +3471,18 @@
|
||||
"id": "app.plugin.activate.app_error",
|
||||
"translation": "Unable to activate extracted plugin. Plugin may already exist and be activated."
|
||||
},
|
||||
{
|
||||
"id": "app.plugin.get_plugins.app_error",
|
||||
"translation": "Unable to get plugins"
|
||||
},
|
||||
{
|
||||
"id": "app.plugin.not_installed.app_error",
|
||||
"translation": "Plugin is not installed"
|
||||
},
|
||||
{
|
||||
"id": "app.plugin.config.app_error",
|
||||
"translation": "Error saving plugin state in config"
|
||||
},
|
||||
{
|
||||
"id": "app.plugin.deactivate.app_error",
|
||||
"translation": "Unable to deactivate plugin"
|
||||
|
||||
@@ -3150,12 +3150,12 @@ func (c *Client4) UploadPlugin(file io.Reader) (*Manifest, *Response) {
|
||||
|
||||
// GetPlugins will return a list of plugin manifests for currently active plugins.
|
||||
// WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE.
|
||||
func (c *Client4) GetPlugins() ([]*Manifest, *Response) {
|
||||
func (c *Client4) GetPlugins() (*PluginsResponse, *Response) {
|
||||
if r, err := c.DoApiGet(c.GetPluginsRoute(), ""); err != nil {
|
||||
return nil, BuildErrorResponse(r, err)
|
||||
} else {
|
||||
defer closeBody(r)
|
||||
return ManifestListFromJson(r.Body), BuildResponse(r)
|
||||
return PluginsResponseFromJson(r.Body), BuildResponse(r)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3180,3 +3180,25 @@ func (c *Client4) GetWebappPlugins() ([]*Manifest, *Response) {
|
||||
return ManifestListFromJson(r.Body), BuildResponse(r)
|
||||
}
|
||||
}
|
||||
|
||||
// ActivatePlugin will activate an plugin installed.
|
||||
// WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE.
|
||||
func (c *Client4) ActivatePlugin(id string) (bool, *Response) {
|
||||
if r, err := c.DoApiPost(c.GetPluginRoute(id)+"/activate", ""); err != nil {
|
||||
return false, BuildErrorResponse(r, err)
|
||||
} else {
|
||||
defer closeBody(r)
|
||||
return CheckStatusOK(r), BuildResponse(r)
|
||||
}
|
||||
}
|
||||
|
||||
// DeactivatePlugin will deactivate an active plugin.
|
||||
// WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE.
|
||||
func (c *Client4) DeactivatePlugin(id string) (bool, *Response) {
|
||||
if r, err := c.DoApiPost(c.GetPluginRoute(id)+"/deactivate", ""); err != nil {
|
||||
return false, BuildErrorResponse(r, err)
|
||||
} else {
|
||||
defer closeBody(r)
|
||||
return CheckStatusOK(r), BuildResponse(r)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -504,9 +504,14 @@ type JobSettings struct {
|
||||
RunScheduler *bool
|
||||
}
|
||||
|
||||
type PluginState struct {
|
||||
Enable bool
|
||||
}
|
||||
|
||||
type PluginSettings struct {
|
||||
Enable *bool
|
||||
Plugins map[string]interface{}
|
||||
Enable *bool
|
||||
Plugins map[string]interface{}
|
||||
PluginStates map[string]*PluginState
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
@@ -1454,6 +1459,10 @@ func (o *Config) SetDefaults() {
|
||||
o.PluginSettings.Plugins = make(map[string]interface{})
|
||||
}
|
||||
|
||||
if o.PluginSettings.PluginStates == nil {
|
||||
o.PluginSettings.PluginStates = make(map[string]*PluginState)
|
||||
}
|
||||
|
||||
o.defaultWebrtcSettings()
|
||||
}
|
||||
|
||||
|
||||
31
model/plugins_response.go
Normal file
31
model/plugins_response.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
)
|
||||
|
||||
type PluginsResponse struct {
|
||||
Active []*Manifest `json:"active"`
|
||||
Inactive []*Manifest `json:"inactive"`
|
||||
}
|
||||
|
||||
func (m *PluginsResponse) ToJson() string {
|
||||
b, err := json.Marshal(m)
|
||||
if err != nil {
|
||||
return ""
|
||||
} else {
|
||||
return string(b)
|
||||
}
|
||||
}
|
||||
|
||||
func PluginsResponseFromJson(data io.Reader) *PluginsResponse {
|
||||
decoder := json.NewDecoder(data)
|
||||
var m PluginsResponse
|
||||
err := decoder.Decode(&m)
|
||||
if err == nil {
|
||||
return &m
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
31
model/plugins_response_test.go
Normal file
31
model/plugins_response_test.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestPluginsResponseJson(t *testing.T) {
|
||||
manifest := &Manifest{
|
||||
Id: "theid",
|
||||
Backend: &ManifestBackend{
|
||||
Executable: "theexecutable",
|
||||
},
|
||||
Webapp: &ManifestWebapp{
|
||||
BundlePath: "thebundlepath",
|
||||
},
|
||||
}
|
||||
|
||||
response := &PluginsResponse{
|
||||
Active: []*Manifest{manifest},
|
||||
Inactive: []*Manifest{},
|
||||
}
|
||||
|
||||
json := response.ToJson()
|
||||
newResponse := PluginsResponseFromJson(strings.NewReader(json))
|
||||
assert.Equal(t, newResponse, response)
|
||||
assert.Equal(t, newResponse.ToJson(), json)
|
||||
assert.Equal(t, PluginsResponseFromJson(strings.NewReader("junk")), (*PluginsResponse)(nil))
|
||||
}
|
||||
@@ -89,6 +89,20 @@ func (env *Environment) ActivePluginIds() (ids []string) {
|
||||
return
|
||||
}
|
||||
|
||||
// Returns true if the plugin is active, false otherwise.
|
||||
func (env *Environment) IsPluginActive(pluginId string) bool {
|
||||
env.mutex.RLock()
|
||||
defer env.mutex.RUnlock()
|
||||
|
||||
for id := range env.activePlugins {
|
||||
if id == pluginId {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Activates the plugin with the given id.
|
||||
func (env *Environment) ActivatePlugin(id string) error {
|
||||
env.mutex.Lock()
|
||||
|
||||
@@ -152,10 +152,12 @@ func TestEnvironment(t *testing.T) {
|
||||
activePlugins = env.ActivePlugins()
|
||||
assert.Len(t, activePlugins, 1)
|
||||
assert.Error(t, env.ActivatePlugin("foo"))
|
||||
assert.True(t, env.IsPluginActive("foo"))
|
||||
|
||||
hooks.On("OnDeactivate").Return(nil)
|
||||
assert.NoError(t, env.DeactivatePlugin("foo"))
|
||||
assert.Error(t, env.DeactivatePlugin("foo"))
|
||||
assert.False(t, env.IsPluginActive("foo"))
|
||||
|
||||
assert.NoError(t, env.ActivatePlugin("foo"))
|
||||
assert.Equal(t, env.ActivePluginIds(), []string{"foo"})
|
||||
|
||||
Reference in New Issue
Block a user