[MM-52924] Implement ConfigurationWillBeSaved plugin hook (#23567)

* Implement ConfigurationWillBeSaved plugin hook

* Add comment

* Update comment

* Fix potential nil dereference if plugin environment is unset

* Address PR review
Этот коммит содержится в:
Claudio Costa
2023-06-12 18:23:02 -06:00
коммит произвёл GitHub
родитель d0ad46b496
Коммит 62a3ee8adc
10 изменённых файлов: 267 добавлений и 9 удалений

Просмотреть файл

@@ -1037,6 +1037,42 @@ func (s *hooksRPCServer) GetTopicMetadataByIds(args *Z_GetTopicMetadataByIdsArgs
return nil
}
func init() {
hookNameToId["ConfigurationWillBeSaved"] = ConfigurationWillBeSavedID
}
type Z_ConfigurationWillBeSavedArgs struct {
A *model.Config
}
type Z_ConfigurationWillBeSavedReturns struct {
A *model.Config
B error
}
func (g *hooksRPCClient) ConfigurationWillBeSaved(newCfg *model.Config) (*model.Config, error) {
_args := &Z_ConfigurationWillBeSavedArgs{newCfg}
_returns := &Z_ConfigurationWillBeSavedReturns{}
if g.implemented[ConfigurationWillBeSavedID] {
if err := g.client.Call("Plugin.ConfigurationWillBeSaved", _args, _returns); err != nil {
g.log.Error("RPC call ConfigurationWillBeSaved to plugin failed.", mlog.Err(err))
}
}
return _returns.A, _returns.B
}
func (s *hooksRPCServer) ConfigurationWillBeSaved(args *Z_ConfigurationWillBeSavedArgs, returns *Z_ConfigurationWillBeSavedReturns) error {
if hook, ok := s.impl.(interface {
ConfigurationWillBeSaved(newCfg *model.Config) (*model.Config, error)
}); ok {
returns.A, returns.B = hook.ConfigurationWillBeSaved(args.A)
returns.B = encodableError(returns.B)
} else {
return encodableError(fmt.Errorf("Hook ConfigurationWillBeSaved called but not implemented."))
}
return nil
}
type Z_RegisterCommandArgs struct {
A *model.Command
}

Просмотреть файл

@@ -49,6 +49,7 @@ const (
GetTopicRedirectID = 31
GetCollectionMetadataByIdsID = 32
GetTopicMetadataByIdsID = 33
ConfigurationWillBeSavedID = 34
TotalHooksID = iota
)
@@ -336,4 +337,11 @@ type Hooks interface {
//
// Minimum server version: 7.6
GetTopicMetadataByIds(c *Context, topicType string, topicIds []string) (map[string]*model.TopicMetadata, error)
// ConfigurationWillBeSaved is invoked before saving the configuration to the
// backing store.
// An error can be returned to reject the operation. Additionally, a new
// config object can be returned to be stored in place of the provided one.
// Minimum server version: 8.0
ConfigurationWillBeSaved(newCfg *model.Config) (*model.Config, error)
}

Просмотреть файл

@@ -253,3 +253,10 @@ func (hooks *hooksTimerLayer) GetTopicMetadataByIds(c *Context, topicType string
hooks.recordTime(startTime, "GetTopicMetadataByIds", _returnsB == nil)
return _returnsA, _returnsB
}
func (hooks *hooksTimerLayer) ConfigurationWillBeSaved(newCfg *model.Config) (*model.Config, error) {
startTime := timePkg.Now()
_returnsA, _returnsB := hooks.hooksImpl.ConfigurationWillBeSaved(newCfg)
hooks.recordTime(startTime, "ConfigurationWillBeSaved", _returnsB == nil)
return _returnsA, _returnsB
}

Просмотреть файл

@@ -25,6 +25,32 @@ func (_m *Hooks) ChannelHasBeenCreated(c *plugin.Context, channel *model.Channel
_m.Called(c, channel)
}
// ConfigurationWillBeSaved provides a mock function with given fields: newCfg
func (_m *Hooks) ConfigurationWillBeSaved(newCfg *model.Config) (*model.Config, error) {
ret := _m.Called(newCfg)
var r0 *model.Config
var r1 error
if rf, ok := ret.Get(0).(func(*model.Config) (*model.Config, error)); ok {
return rf(newCfg)
}
if rf, ok := ret.Get(0).(func(*model.Config) *model.Config); ok {
r0 = rf(newCfg)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.Config)
}
}
if rf, ok := ret.Get(1).(func(*model.Config) error); ok {
r1 = rf(newCfg)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// ExecuteCommand provides a mock function with given fields: c, args
func (_m *Hooks) ExecuteCommand(c *plugin.Context, args *model.CommandArgs) (*model.CommandResponse, *model.AppError) {
ret := _m.Called(c, args)

Просмотреть файл

@@ -138,6 +138,10 @@ type GetTopicMetadataByIdsIFace interface {
GetTopicMetadataByIds(c *Context, topicType string, topicIds []string) (map[string]*model.TopicMetadata, error)
}
type ConfigurationWillBeSavedIFace interface {
ConfigurationWillBeSaved(newCfg *model.Config) (*model.Config, error)
}
type HooksAdapter struct {
implemented map[int]struct{}
productHooks any
@@ -430,6 +434,15 @@ func NewAdapter(productHooks any) (*HooksAdapter, error) {
return nil, errors.New("hook has GetTopicMetadataByIds method but does not implement plugin.GetTopicMetadataByIds interface")
}
// Assessing the type of the productHooks if it individually implements ConfigurationWillBeSaved interface.
tt = reflect.TypeOf((*ConfigurationWillBeSavedIFace)(nil)).Elem()
if ft.Implements(tt) {
a.implemented[ConfigurationWillBeSavedID] = struct{}{}
} else if _, ok := ft.MethodByName("ConfigurationWillBeSaved"); ok {
return nil, errors.New("hook has ConfigurationWillBeSaved method but does not implement plugin.ConfigurationWillBeSaved interface")
}
return a, nil
}
@@ -711,3 +724,12 @@ func (a *HooksAdapter) GetTopicMetadataByIds(c *Context, topicType string, topic
return a.productHooks.(GetTopicMetadataByIdsIFace).GetTopicMetadataByIds(c, topicType, topicIds)
}
func (a *HooksAdapter) ConfigurationWillBeSaved(newCfg *model.Config) (*model.Config, error) {
if _, ok := a.implemented[ConfigurationWillBeSavedID]; !ok {
panic("product hooks must implement ConfigurationWillBeSaved")
}
return a.productHooks.(ConfigurationWillBeSavedIFace).ConfigurationWillBeSaved(newCfg)
}