[MM-11861] Design & implement a better way for plugins to update their own configuration (#9712)
* [MM-11861] Design & implement a better way for plugins to update their own configuration Added GetPluginConfig and SavePluginConfig plugin APIs. Added test cases for testing new APIs. * Fixed gofmt error * Minor changes requested in PR
Этот коммит содержится в:
коммит произвёл
Jesse Hallam
родитель
a50e8ac5b9
Коммит
7a6f957638
@@ -84,6 +84,20 @@ func (api *PluginAPI) SaveConfig(config *model.Config) *model.AppError {
|
||||
return api.app.SaveConfig(config, true)
|
||||
}
|
||||
|
||||
func (api *PluginAPI) GetPluginConfig() map[string]interface{} {
|
||||
cfg := api.app.GetConfig()
|
||||
if pluginConfig, isOk := cfg.PluginSettings.Plugins[api.manifest.Id]; isOk {
|
||||
return pluginConfig
|
||||
}
|
||||
return map[string]interface{}{}
|
||||
}
|
||||
|
||||
func (api *PluginAPI) SavePluginConfig(pluginConfig map[string]interface{}) *model.AppError {
|
||||
cfg := api.app.GetConfig()
|
||||
cfg.PluginSettings.Plugins[api.manifest.Id] = pluginConfig
|
||||
return api.app.SaveConfig(cfg, true)
|
||||
}
|
||||
|
||||
func (api *PluginAPI) GetServerVersion() string {
|
||||
return model.CurrentVersion
|
||||
}
|
||||
|
||||
@@ -63,6 +63,84 @@ func TestPluginAPIUpdateUserStatus(t *testing.T) {
|
||||
assert.Nil(t, status)
|
||||
}
|
||||
|
||||
func TestPluginAPISavePluginConfig(t *testing.T) {
|
||||
th := Setup().InitBasic()
|
||||
defer th.TearDown()
|
||||
|
||||
manifest := &model.Manifest{
|
||||
Id: "pluginid",
|
||||
SettingsSchema: &model.PluginSettingsSchema{
|
||||
Settings: []*model.PluginSetting{
|
||||
{Key: "MyStringSetting", Type: "text"},
|
||||
{Key: "MyIntSetting", Type: "text"},
|
||||
{Key: "MyBoolSetting", Type: "bool"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
api := NewPluginAPI(th.App, manifest)
|
||||
|
||||
pluginConfigJsonString := `{"mystringsetting": "str", "MyIntSetting": 32, "myboolsetting": true}`
|
||||
|
||||
var pluginConfig map[string]interface{}
|
||||
if err := json.Unmarshal([]byte(pluginConfigJsonString), &pluginConfig); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := api.SavePluginConfig(pluginConfig); err != nil{
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
type Configuration struct {
|
||||
MyStringSetting string
|
||||
MyIntSetting int
|
||||
MyBoolSetting bool
|
||||
}
|
||||
|
||||
savedConfiguration := new(Configuration)
|
||||
if err := api.LoadPluginConfiguration(savedConfiguration); err != nil{
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expectedConfiguration := new(Configuration)
|
||||
if err := json.Unmarshal([]byte(pluginConfigJsonString), &expectedConfiguration); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assert.Equal(t, expectedConfiguration, savedConfiguration)
|
||||
}
|
||||
|
||||
func TestPluginAPIGetPluginConfig(t *testing.T) {
|
||||
th := Setup().InitBasic()
|
||||
defer th.TearDown()
|
||||
|
||||
manifest := &model.Manifest{
|
||||
Id: "pluginid",
|
||||
SettingsSchema: &model.PluginSettingsSchema{
|
||||
Settings: []*model.PluginSetting{
|
||||
{Key: "MyStringSetting", Type: "text"},
|
||||
{Key: "MyIntSetting", Type: "text"},
|
||||
{Key: "MyBoolSetting", Type: "bool"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
api := NewPluginAPI(th.App, manifest)
|
||||
|
||||
pluginConfigJsonString := `{"mystringsetting": "str", "MyIntSetting": 32, "myboolsetting": true}`
|
||||
var pluginConfig map[string]interface{}
|
||||
|
||||
if err := json.Unmarshal([]byte(pluginConfigJsonString), &pluginConfig); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
th.App.UpdateConfig(func(cfg *model.Config) {
|
||||
cfg.PluginSettings.Plugins["pluginid"] = pluginConfig
|
||||
})
|
||||
|
||||
savedPluginConfig := api.GetPluginConfig()
|
||||
assert.Equal(t, pluginConfig, savedPluginConfig)
|
||||
}
|
||||
|
||||
func TestPluginAPILoadPluginConfiguration(t *testing.T) {
|
||||
th := Setup().InitBasic()
|
||||
defer th.TearDown()
|
||||
|
||||
@@ -34,6 +34,16 @@ type API interface {
|
||||
// SaveConfig sets the given config and persists the changes
|
||||
SaveConfig(config *model.Config) *model.AppError
|
||||
|
||||
// GetPluginConfig fetches the currently persisted config of plugin
|
||||
//
|
||||
// Minimum server version: 5.6
|
||||
GetPluginConfig() map[string]interface{}
|
||||
|
||||
// SavePluginConfig sets the given config for plugin and persists the changes
|
||||
//
|
||||
// Minimum server version: 5.6
|
||||
SavePluginConfig(config map[string]interface{}) *model.AppError
|
||||
|
||||
// GetServerVersion return the current Mattermost server version
|
||||
//
|
||||
// Minimum server version: 5.4
|
||||
|
||||
@@ -656,6 +656,61 @@ func (s *apiRPCServer) SaveConfig(args *Z_SaveConfigArgs, returns *Z_SaveConfigR
|
||||
return nil
|
||||
}
|
||||
|
||||
type Z_GetPluginConfigArgs struct {
|
||||
}
|
||||
|
||||
type Z_GetPluginConfigReturns struct {
|
||||
A map[string]interface{}
|
||||
}
|
||||
|
||||
func (g *apiRPCClient) GetPluginConfig() map[string]interface{} {
|
||||
_args := &Z_GetPluginConfigArgs{}
|
||||
_returns := &Z_GetPluginConfigReturns{}
|
||||
if err := g.client.Call("Plugin.GetPluginConfig", _args, _returns); err != nil {
|
||||
log.Printf("RPC call to GetPluginConfig API failed: %s", err.Error())
|
||||
}
|
||||
return _returns.A
|
||||
}
|
||||
|
||||
func (s *apiRPCServer) GetPluginConfig(args *Z_GetPluginConfigArgs, returns *Z_GetPluginConfigReturns) error {
|
||||
if hook, ok := s.impl.(interface {
|
||||
GetPluginConfig() map[string]interface{}
|
||||
}); ok {
|
||||
returns.A = hook.GetPluginConfig()
|
||||
} else {
|
||||
return encodableError(fmt.Errorf("API GetPluginConfig called but not implemented."))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Z_SavePluginConfigArgs struct {
|
||||
A map[string]interface{}
|
||||
}
|
||||
|
||||
type Z_SavePluginConfigReturns struct {
|
||||
A *model.AppError
|
||||
}
|
||||
|
||||
func (g *apiRPCClient) SavePluginConfig(config map[string]interface{}) *model.AppError {
|
||||
_args := &Z_SavePluginConfigArgs{config}
|
||||
_returns := &Z_SavePluginConfigReturns{}
|
||||
if err := g.client.Call("Plugin.SavePluginConfig", _args, _returns); err != nil {
|
||||
log.Printf("RPC call to SavePluginConfig API failed: %s", err.Error())
|
||||
}
|
||||
return _returns.A
|
||||
}
|
||||
|
||||
func (s *apiRPCServer) SavePluginConfig(args *Z_SavePluginConfigArgs, returns *Z_SavePluginConfigReturns) error {
|
||||
if hook, ok := s.impl.(interface {
|
||||
SavePluginConfig(config map[string]interface{}) *model.AppError
|
||||
}); ok {
|
||||
returns.A = hook.SavePluginConfig(args.A)
|
||||
} else {
|
||||
return encodableError(fmt.Errorf("API SavePluginConfig called but not implemented."))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Z_GetServerVersionArgs struct {
|
||||
}
|
||||
|
||||
|
||||
@@ -581,6 +581,20 @@ func (_m *API) GetConfig() *model.Config {
|
||||
return r0
|
||||
}
|
||||
|
||||
// GetPluginConfig provides a mock function with given fields:
|
||||
func (_m *API) GetPluginConfig() map[string]interface{} {
|
||||
ret := _m.Called()
|
||||
|
||||
var r0 map[string]interface{}
|
||||
if rf, ok := ret.Get(0).(func() map[string]interface{}); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
r0 = ret.Get(0).(map[string]interface{})
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// GetDirectChannel provides a mock function with given fields: userId1, userId2
|
||||
func (_m *API) GetDirectChannel(userId1 string, userId2 string) (*model.Channel, *model.AppError) {
|
||||
ret := _m.Called(userId1, userId2)
|
||||
@@ -1819,6 +1833,22 @@ func (_m *API) SaveConfig(config *model.Config) *model.AppError {
|
||||
return r0
|
||||
}
|
||||
|
||||
// SavePluginConfig provides a mock function with given fields: pluginConfig
|
||||
func (_m *API) SavePluginConfig(pluginConfig map[string]interface{}) *model.AppError {
|
||||
ret := _m.Called(pluginConfig)
|
||||
|
||||
var r0 *model.AppError
|
||||
if rf, ok := ret.Get(0).(func(map[string]interface{}) *model.AppError); ok {
|
||||
r0 = rf(pluginConfig)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*model.AppError)
|
||||
}
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// SearchChannels provides a mock function with given fields: teamId, term
|
||||
func (_m *API) SearchChannels(teamId string, term string) (*model.ChannelList, *model.AppError) {
|
||||
ret := _m.Called(teamId, term)
|
||||
|
||||
Ссылка в новой задаче
Block a user