Add plugin methods to plugin API (#9744)

This commit is contained in:
Hanzei
2018-11-08 10:17:07 -08:00
committed by Christopher Speller
parent 93e581d642
commit e67d89b9a8
7 changed files with 390 additions and 4 deletions
+35
View File
@@ -438,6 +438,41 @@ func (api *PluginAPI) GetEmojiImage(emojiId string) ([]byte, string, *model.AppE
return api.app.GetEmojiImage(emojiId)
}
// Plugin Section
func (api *PluginAPI) GetPlugins() ([]*model.Manifest, *model.AppError) {
plugins, err := api.app.GetPlugins()
if err != nil {
return nil, err
}
var manifests []*model.Manifest
for _, manifest := range plugins.Active {
manifests = append(manifests, &manifest.Manifest)
}
for _, manifest := range plugins.Inactive {
manifests = append(manifests, &manifest.Manifest)
}
return manifests, nil
}
func (api *PluginAPI) EnablePlugin(id string) *model.AppError {
return api.app.EnablePlugin(id)
}
func (api *PluginAPI) DisablePlugin(id string) *model.AppError {
return api.app.DisablePlugin(id)
}
func (api *PluginAPI) RemovePlugin(id string) *model.AppError {
return api.app.RemovePlugin(id)
}
func (api *PluginAPI) GetPluginStatus(id string) (*model.PluginStatus, *model.AppError) {
return api.app.GetPluginStatus(id)
}
// KV Store Section
func (api *PluginAPI) KVSet(key string, value []byte) *model.AppError {
return api.app.SetPluginKey(api.id, key, value)
}
+63 -1
View File
@@ -5,6 +5,7 @@ package app
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"path/filepath"
@@ -31,7 +32,10 @@ func setupPluginApiTest(t *testing.T, pluginCode string, pluginManifest string,
compileGo(t, pluginCode, backend)
ioutil.WriteFile(filepath.Join(pluginDir, pluginId, "plugin.json"), []byte(pluginManifest), 0600)
env.Activate(pluginId)
manifest, activated, reterr := env.Activate(pluginId)
require.Nil(t, reterr)
require.NotNil(t, manifest)
require.True(t, activated)
app.Srv.Plugins = env
}
@@ -215,3 +219,61 @@ func TestPluginAPIGetProfileImage(t *testing.T) {
require.NotNil(t, err)
require.Nil(t, data)
}
func TestPluginAPIGetPlugins(t *testing.T) {
th := Setup().InitBasic()
defer th.TearDown()
api := th.SetupPluginAPI()
pluginCode := `
package main
import (
"github.com/mattermost/mattermost-server/plugin"
)
type MyPlugin struct {
plugin.MattermostPlugin
}
func main() {
plugin.ClientMain(&MyPlugin{})
}
`
pluginDir, err := ioutil.TempDir("", "")
require.NoError(t, err)
webappPluginDir, err := ioutil.TempDir("", "")
require.NoError(t, err)
defer os.RemoveAll(pluginDir)
defer os.RemoveAll(webappPluginDir)
env, err := plugin.NewEnvironment(th.App.NewPluginAPI, pluginDir, webappPluginDir, th.App.Log)
require.NoError(t, err)
pluginIDs := []string{"pluginid1", "pluginid2", "pluginid3"}
var pluginManifests []*model.Manifest
for _, pluginID := range pluginIDs {
backend := filepath.Join(pluginDir, pluginID, "backend.exe")
compileGo(t, pluginCode, backend)
ioutil.WriteFile(filepath.Join(pluginDir, pluginID, "plugin.json"), []byte(fmt.Sprintf(`{"id": "%s", "server": {"executable": "backend.exe"}}`, pluginID)), 0600)
manifest, activated, reterr := env.Activate(pluginID)
require.Nil(t, reterr)
require.NotNil(t, manifest)
require.True(t, activated)
pluginManifests = append(pluginManifests, manifest)
}
th.App.Srv.Plugins = env
// Decative the last one for testing
sucess := env.Deactivate(pluginIDs[len(pluginIDs)-1])
require.True(t, sucess)
// check existing user first
plugins, err := api.GetPlugins()
assert.Nil(t, err)
assert.NotEmpty(t, plugins)
assert.Equal(t, pluginManifests, plugins)
}
+21
View File
@@ -9,6 +9,27 @@ import (
"github.com/mattermost/mattermost-server/model"
)
// GetPluginStatus returns the status for a plugin installed on this server.
func (a *App) GetPluginStatus(id string) (*model.PluginStatus, *model.AppError) {
if a.Srv.Plugins == nil || !*a.Config().PluginSettings.Enable {
return nil, model.NewAppError("GetPluginStatus", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented)
}
pluginStatuses, err := a.Srv.Plugins.Statuses()
if err != nil {
return nil, model.NewAppError("GetPluginStatus", "app.plugin.get_statuses.app_error", nil, err.Error(), http.StatusInternalServerError)
}
// Add our cluster ID
for _, status := range pluginStatuses {
if status.PluginId == id {
status.ClusterId = a.GetClusterId()
return status, nil
}
}
return nil, model.NewAppError("GetPluginStatus", "app.plugin.not_installed.app_error", nil, "", http.StatusBadRequest)
}
// GetPluginStatuses returns the status for plugins installed on this server.
func (a *App) GetPluginStatuses() (model.PluginStatuses, *model.AppError) {
if a.Srv.Plugins == nil || !*a.Config().PluginSettings.Enable {
+3 -3
View File
@@ -3771,7 +3771,7 @@ func (c *Client4) GetPluginStatuses() (PluginStatuses, *Response) {
}
}
// RemovePlugin will deactivate and delete a plugin.
// RemovePlugin will disable and delete a plugin.
// WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE.
func (c *Client4) RemovePlugin(id string) (bool, *Response) {
if r, err := c.DoApiDelete(c.GetPluginRoute(id)); err != nil {
@@ -3793,7 +3793,7 @@ func (c *Client4) GetWebappPlugins() ([]*Manifest, *Response) {
}
}
// ActivatePlugin will activate an plugin installed.
// EnablePlugin will enable an plugin installed.
// WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE.
func (c *Client4) EnablePlugin(id string) (bool, *Response) {
if r, err := c.DoApiPost(c.GetPluginRoute(id)+"/enable", ""); err != nil {
@@ -3804,7 +3804,7 @@ func (c *Client4) EnablePlugin(id string) (bool, *Response) {
}
}
// DeactivatePlugin will deactivate an active plugin.
// DisablePlugin will disable an enabled plugin.
// WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE.
func (c *Client4) DisablePlugin(id string) (bool, *Response) {
if r, err := c.DoApiPost(c.GetPluginRoute(id)+"/disable", ""); err != nil {
+29
View File
@@ -314,6 +314,35 @@ type API interface {
// Minimum server version: 5.6
UploadFile(data []byte, channelId string, filename string) (*model.FileInfo, *model.AppError)
// Plugin Section
// GetPlugins will return a list of plugin manifests for currently active plugins.
//
// Minimum server version: 5.6
GetPlugins() ([]*model.Manifest, *model.AppError)
// EnablePlugin will enable an plugin installed.
//
// Minimum server version: 5.6
EnablePlugin(id string) *model.AppError
// DisablePlugin will disable an enabled plugin.
//
// Minimum server version: 5.6
DisablePlugin(id string) *model.AppError
// RemovePlugin will disable and delete a plugin.
//
// Minimum server version: 5.6
RemovePlugin(id string) *model.AppError
// GetPluginStatus will return the status of a plugin.
//
// Minimum server version: 5.6
GetPluginStatus(id string) (*model.PluginStatus, *model.AppError)
// KV Store Section
// KVSet will store a key-value pair, unique per plugin.
KVSet(key string, value []byte) *model.AppError
+141
View File
@@ -2728,6 +2728,147 @@ func (s *apiRPCServer) UploadFile(args *Z_UploadFileArgs, returns *Z_UploadFileR
return nil
}
type Z_GetPluginsArgs struct {
}
type Z_GetPluginsReturns struct {
A []*model.Manifest
B *model.AppError
}
func (g *apiRPCClient) GetPlugins() ([]*model.Manifest, *model.AppError) {
_args := &Z_GetPluginsArgs{}
_returns := &Z_GetPluginsReturns{}
if err := g.client.Call("Plugin.GetPlugins", _args, _returns); err != nil {
log.Printf("RPC call to GetPlugins API failed: %s", err.Error())
}
return _returns.A, _returns.B
}
func (s *apiRPCServer) GetPlugins(args *Z_GetPluginsArgs, returns *Z_GetPluginsReturns) error {
if hook, ok := s.impl.(interface {
GetPlugins() ([]*model.Manifest, *model.AppError)
}); ok {
returns.A, returns.B = hook.GetPlugins()
} else {
return encodableError(fmt.Errorf("API GetPlugins called but not implemented."))
}
return nil
}
type Z_GetPluginStatusArgs struct {
A string
}
type Z_GetPluginStatusReturns struct {
A *model.PluginStatus
B *model.AppError
}
func (g *apiRPCClient) GetPluginStatus(id string) (*model.PluginStatus, *model.AppError) {
_args := &Z_GetPluginStatusArgs{id}
_returns := &Z_GetPluginStatusReturns{}
if err := g.client.Call("Plugin.GetPluginStatus", _args, _returns); err != nil {
log.Printf("RPC call to GetPluginStatus API failed: %s", err.Error())
}
return _returns.A, _returns.B
}
func (s *apiRPCServer) GetPluginStatus(args *Z_GetPluginStatusArgs, returns *Z_GetPluginStatusReturns) error {
if hook, ok := s.impl.(interface {
GetPluginStatus(id string) (*model.PluginStatus, *model.AppError)
}); ok {
returns.A, returns.B = hook.GetPluginStatus(args.A)
} else {
return encodableError(fmt.Errorf("API GetPluginStatus called but not implemented."))
}
return nil
}
type Z_EnablePluginArgs struct {
A string
}
type Z_EnablePluginReturns struct {
A *model.AppError
}
func (g *apiRPCClient) EnablePlugin(id string) *model.AppError {
_args := &Z_EnablePluginArgs{id}
_returns := &Z_EnablePluginReturns{}
if err := g.client.Call("Plugin.EnablePlugin", _args, _returns); err != nil {
log.Printf("RPC call to EnablePlugin API failed: %s", err.Error())
}
return _returns.A
}
func (s *apiRPCServer) EnablePlugin(args *Z_EnablePluginArgs, returns *Z_EnablePluginReturns) error {
if hook, ok := s.impl.(interface {
EnablePlugin(id string) *model.AppError
}); ok {
returns.A = hook.EnablePlugin(args.A)
} else {
return encodableError(fmt.Errorf("API EnablePlugin called but not implemented."))
}
return nil
}
type Z_DisablePluginArgs struct {
A string
}
type Z_DisablePluginReturns struct {
A *model.AppError
}
func (g *apiRPCClient) DisablePlugin(id string) *model.AppError {
_args := &Z_DisablePluginArgs{id}
_returns := &Z_DisablePluginReturns{}
if err := g.client.Call("Plugin.DisablePlugin", _args, _returns); err != nil {
log.Printf("RPC call to DisablePlugin API failed: %s", err.Error())
}
return _returns.A
}
func (s *apiRPCServer) DisablePlugin(args *Z_DisablePluginArgs, returns *Z_DisablePluginReturns) error {
if hook, ok := s.impl.(interface {
DisablePlugin(id string) *model.AppError
}); ok {
returns.A = hook.DisablePlugin(args.A)
} else {
return encodableError(fmt.Errorf("API DisablePlugin called but not implemented."))
}
return nil
}
type Z_RemovePluginArgs struct {
A string
}
type Z_RemovePluginReturns struct {
A *model.AppError
}
func (g *apiRPCClient) RemovePlugin(id string) *model.AppError {
_args := &Z_RemovePluginArgs{id}
_returns := &Z_RemovePluginReturns{}
if err := g.client.Call("Plugin.RemovePlugin", _args, _returns); err != nil {
log.Printf("RPC call to RemovePlugin API failed: %s", err.Error())
}
return _returns.A
}
func (s *apiRPCServer) RemovePlugin(args *Z_RemovePluginArgs, returns *Z_RemovePluginReturns) error {
if hook, ok := s.impl.(interface {
RemovePlugin(id string) *model.AppError
}); ok {
returns.A = hook.RemovePlugin(args.A)
} else {
return encodableError(fmt.Errorf("API RemovePlugin called but not implemented."))
}
return nil
}
type Z_KVSetArgs struct {
A string
B []byte
+98
View File
@@ -333,6 +333,38 @@ func (_m *API) DeleteUser(userId string) *model.AppError {
return r0
}
// DisablePlugin provides a mock function with given fields: id
func (_m *API) DisablePlugin(id string) *model.AppError {
ret := _m.Called(id)
var r0 *model.AppError
if rf, ok := ret.Get(0).(func(string) *model.AppError); ok {
r0 = rf(id)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.AppError)
}
}
return r0
}
// EnablePlugin provides a mock function with given fields: id
func (_m *API) EnablePlugin(id string) *model.AppError {
ret := _m.Called(id)
var r0 *model.AppError
if rf, ok := ret.Get(0).(func(string) *model.AppError); ok {
r0 = rf(id)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.AppError)
}
}
return r0
}
// GetChannel provides a mock function with given fields: channelId
func (_m *API) GetChannel(channelId string) (*model.Channel, *model.AppError) {
ret := _m.Called(channelId)
@@ -779,6 +811,56 @@ func (_m *API) GetLDAPUserAttributes(userId string, attributes []string) (map[st
return r0, r1
}
// GetPluginStatus provides a mock function with given fields: id
func (_m *API) GetPluginStatus(id string) (*model.PluginStatus, *model.AppError) {
ret := _m.Called(id)
var r0 *model.PluginStatus
if rf, ok := ret.Get(0).(func(string) *model.PluginStatus); ok {
r0 = rf(id)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.PluginStatus)
}
}
var r1 *model.AppError
if rf, ok := ret.Get(1).(func(string) *model.AppError); ok {
r1 = rf(id)
} else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)
}
}
return r0, r1
}
// GetPlugins provides a mock function with given fields:
func (_m *API) GetPlugins() ([]*model.Manifest, *model.AppError) {
ret := _m.Called()
var r0 []*model.Manifest
if rf, ok := ret.Get(0).(func() []*model.Manifest); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]*model.Manifest)
}
}
var r1 *model.AppError
if rf, ok := ret.Get(1).(func() *model.AppError); ok {
r1 = rf()
} else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)
}
}
return r0, r1
}
// GetPost provides a mock function with given fields: postId
func (_m *API) GetPost(postId string) (*model.Post, *model.AppError) {
ret := _m.Called(postId)
@@ -1664,6 +1746,22 @@ func (_m *API) RegisterCommand(command *model.Command) error {
return r0
}
// RemovePlugin provides a mock function with given fields: id
func (_m *API) RemovePlugin(id string) *model.AppError {
ret := _m.Called(id)
var r0 *model.AppError
if rf, ok := ret.Get(0).(func(string) *model.AppError); ok {
r0 = rf(id)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.AppError)
}
}
return r0
}
// RemoveReaction provides a mock function with given fields: reaction
func (_m *API) RemoveReaction(reaction *model.Reaction) *model.AppError {
ret := _m.Called(reaction)