MM-44953: Refactor EnsureBot to be used from plugin.API (#20521)
The mattermost-plugin-api code also needs to use this. Hence we make it available from plugin.API. https://mattermost.atlassian.net/browse/MM-44953 ```release-note NONE ```
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
b5dec4f4d9
Коммит
4dd2b5f039
@@ -125,6 +125,11 @@ type AppIface interface {
|
|||||||
// activation if inactive anywhere in the cluster.
|
// activation if inactive anywhere in the cluster.
|
||||||
// Notifies cluster peers through config change.
|
// Notifies cluster peers through config change.
|
||||||
EnablePlugin(id string) *model.AppError
|
EnablePlugin(id string) *model.AppError
|
||||||
|
// EnsureBot provides similar functionality with the plugin-api BotService. It doesn't accept
|
||||||
|
// any ensureBotOptions hence it is not required for now.
|
||||||
|
// TODO: Once the focalboard migration completed, we should add this logic to the app and
|
||||||
|
// let plugin-api use the same code
|
||||||
|
EnsureBot(c *request.Context, productID string, bot *model.Bot) (string, error)
|
||||||
// Expand announcements in incoming webhooks from Slack. Those announcements
|
// Expand announcements in incoming webhooks from Slack. Those announcements
|
||||||
// can be found in the text attribute, or in the pretext, text, title and value
|
// can be found in the text attribute, or in the pretext, text, title and value
|
||||||
// attributes of the attachment structure. The Slack attachment structure is
|
// attributes of the attachment structure. The Slack attachment structure is
|
||||||
|
|||||||
24
app/bot.go
24
app/bot.go
@@ -25,11 +25,15 @@ type botServiceWrapper struct {
|
|||||||
app AppIface
|
app AppIface
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *botServiceWrapper) EnsureBot(c *request.Context, productID string, bot *model.Bot) (string, error) {
|
||||||
|
return w.app.EnsureBot(c, productID, bot)
|
||||||
|
}
|
||||||
|
|
||||||
// EnsureBot provides similar functionality with the plugin-api BotService. It doesn't accept
|
// EnsureBot provides similar functionality with the plugin-api BotService. It doesn't accept
|
||||||
// any ensureBotOptions hence it is not required for now.
|
// any ensureBotOptions hence it is not required for now.
|
||||||
// TODO: Once the focalboard migration completed, we should add this logic to the app and
|
// TODO: Once the focalboard migration completed, we should add this logic to the app and
|
||||||
// let plugin-api use the same code
|
// let plugin-api use the same code
|
||||||
func (w *botServiceWrapper) EnsureBot(c *request.Context, productID string, bot *model.Bot) (string, error) {
|
func (a *App) EnsureBot(c *request.Context, productID string, bot *model.Bot) (string, error) {
|
||||||
if bot == nil {
|
if bot == nil {
|
||||||
return "", errors.New("passed a nil bot")
|
return "", errors.New("passed a nil bot")
|
||||||
}
|
}
|
||||||
@@ -38,7 +42,7 @@ func (w *botServiceWrapper) EnsureBot(c *request.Context, productID string, bot
|
|||||||
return "", errors.New("passed a bot with no username")
|
return "", errors.New("passed a bot with no username")
|
||||||
}
|
}
|
||||||
|
|
||||||
botIDBytes, err := w.app.GetPluginKey(productID, botUserKey)
|
botIDBytes, err := a.GetPluginKey(productID, botUserKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@@ -54,7 +58,7 @@ func (w *botServiceWrapper) EnsureBot(c *request.Context, productID string, bot
|
|||||||
Description: &bot.Description,
|
Description: &bot.Description,
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err = w.app.PatchBot(botID, botPatch); err != nil {
|
if _, err = a.PatchBot(botID, botPatch); err != nil {
|
||||||
return "", fmt.Errorf("failed to patch bot: %w", err)
|
return "", fmt.Errorf("failed to patch bot: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,13 +66,13 @@ func (w *botServiceWrapper) EnsureBot(c *request.Context, productID string, bot
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check for an existing bot user with that username. If one exists, then use that.
|
// Check for an existing bot user with that username. If one exists, then use that.
|
||||||
if user, appErr := w.app.GetUserByUsername(bot.Username); appErr == nil && user != nil {
|
if user, appErr := a.GetUserByUsername(bot.Username); appErr == nil && user != nil {
|
||||||
if user.IsBot {
|
if user.IsBot {
|
||||||
if appErr := w.app.SetPluginKey(productID, botUserKey, []byte(user.Id)); appErr != nil {
|
if appErr := a.SetPluginKey(productID, botUserKey, []byte(user.Id)); appErr != nil {
|
||||||
w.app.Srv().Log.Warn("Failed to set claimed bot user id.", mlog.String("userid", user.Id), mlog.Err(appErr))
|
return "", fmt.Errorf("failed to set plugin key: %w", err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
w.app.Srv().Log.Error("Product attempted to use an account that already exists. Convert user to a bot "+
|
a.Srv().Log.Error("Product attempted to use an account that already exists. Convert user to a bot "+
|
||||||
"account in the CLI by running 'mattermost user convert <username> --bot'. If the user is an "+
|
"account in the CLI by running 'mattermost user convert <username> --bot'. If the user is an "+
|
||||||
"existing user account you want to preserve, change its username and restart the Mattermost server, "+
|
"existing user account you want to preserve, change its username and restart the Mattermost server, "+
|
||||||
"after which the plugin will create a bot account with that name. For more information about bot "+
|
"after which the plugin will create a bot account with that name. For more information about bot "+
|
||||||
@@ -81,13 +85,13 @@ func (w *botServiceWrapper) EnsureBot(c *request.Context, productID string, bot
|
|||||||
return user.Id, nil
|
return user.Id, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
createdBot, err := w.app.CreateBot(c, bot)
|
createdBot, err := a.CreateBot(c, bot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("failed to create bot: %w", err)
|
return "", fmt.Errorf("failed to create bot: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if appErr := w.app.SetPluginKey(productID, botUserKey, []byte(createdBot.UserId)); appErr != nil {
|
if appErr := a.SetPluginKey(productID, botUserKey, []byte(createdBot.UserId)); appErr != nil {
|
||||||
w.app.Srv().Log.Warn("Failed to set created bot user id.", mlog.String("userid", createdBot.UserId), mlog.Err(appErr))
|
return "", fmt.Errorf("failed to set plugin key: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return createdBot.UserId, nil
|
return createdBot.UserId, nil
|
||||||
|
|||||||
@@ -3911,6 +3911,28 @@ func (a *OpenTracingAppLayer) EnableUserAccessToken(token *model.UserAccessToken
|
|||||||
return resultVar0
|
return resultVar0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *OpenTracingAppLayer) EnsureBot(c *request.Context, productID string, bot *model.Bot) (string, error) {
|
||||||
|
origCtx := a.ctx
|
||||||
|
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.EnsureBot")
|
||||||
|
|
||||||
|
a.ctx = newCtx
|
||||||
|
a.app.Srv().Store.SetContext(newCtx)
|
||||||
|
defer func() {
|
||||||
|
a.app.Srv().Store.SetContext(origCtx)
|
||||||
|
a.ctx = origCtx
|
||||||
|
}()
|
||||||
|
|
||||||
|
defer span.Finish()
|
||||||
|
resultVar0, resultVar1 := a.app.EnsureBot(c, productID, bot)
|
||||||
|
|
||||||
|
if resultVar1 != nil {
|
||||||
|
span.LogFields(spanlog.Error(resultVar1))
|
||||||
|
ext.Error.Set(span, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultVar0, resultVar1
|
||||||
|
}
|
||||||
|
|
||||||
func (a *OpenTracingAppLayer) EnvironmentConfig(filter func(reflect.StructField) bool) map[string]interface{} {
|
func (a *OpenTracingAppLayer) EnvironmentConfig(filter func(reflect.StructField) bool) map[string]interface{} {
|
||||||
origCtx := a.ctx
|
origCtx := a.ctx
|
||||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.EnvironmentConfig")
|
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.EnvironmentConfig")
|
||||||
|
|||||||
@@ -981,6 +981,10 @@ func (api *PluginAPI) PermanentDeleteBot(userID string) *model.AppError {
|
|||||||
return api.app.PermanentDeleteBot(userID)
|
return api.app.PermanentDeleteBot(userID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (api *PluginAPI) EnsureBotUser(bot *model.Bot) (string, error) {
|
||||||
|
return api.app.EnsureBot(api.ctx, api.id, bot)
|
||||||
|
}
|
||||||
|
|
||||||
func (api *PluginAPI) PublishUserTyping(userID, channelID, parentId string) *model.AppError {
|
func (api *PluginAPI) PublishUserTyping(userID, channelID, parentId string) *model.AppError {
|
||||||
return api.app.PublishUserTyping(userID, channelID, parentId)
|
return api.app.PublishUserTyping(userID, channelID, parentId)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1152,6 +1152,11 @@ type API interface {
|
|||||||
//
|
//
|
||||||
// Minimum server version: 7.0
|
// Minimum server version: 7.0
|
||||||
GetCloudLimits() (*model.ProductLimits, error)
|
GetCloudLimits() (*model.ProductLimits, error)
|
||||||
|
|
||||||
|
// EnsureBotUser updates the bot if it exists, otherwise creates it.
|
||||||
|
//
|
||||||
|
// Minimum server version: 7.1
|
||||||
|
EnsureBotUser(bot *model.Bot) (string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
var handshake = plugin.HandshakeConfig{
|
var handshake = plugin.HandshakeConfig{
|
||||||
|
|||||||
@@ -1232,3 +1232,10 @@ func (api *apiTimerLayer) GetCloudLimits() (*model.ProductLimits, error) {
|
|||||||
api.recordTime(startTime, "GetCloudLimits", _returnsB == nil)
|
api.recordTime(startTime, "GetCloudLimits", _returnsB == nil)
|
||||||
return _returnsA, _returnsB
|
return _returnsA, _returnsB
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (api *apiTimerLayer) EnsureBotUser(bot *model.Bot) (string, error) {
|
||||||
|
startTime := timePkg.Now()
|
||||||
|
_returnsA, _returnsB := api.apiImpl.EnsureBotUser(bot)
|
||||||
|
api.recordTime(startTime, "EnsureBotUser", _returnsB == nil)
|
||||||
|
return _returnsA, _returnsB
|
||||||
|
}
|
||||||
|
|||||||
@@ -5678,3 +5678,33 @@ func (s *apiRPCServer) GetCloudLimits(args *Z_GetCloudLimitsArgs, returns *Z_Get
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Z_EnsureBotUserArgs struct {
|
||||||
|
A *model.Bot
|
||||||
|
}
|
||||||
|
|
||||||
|
type Z_EnsureBotUserReturns struct {
|
||||||
|
A string
|
||||||
|
B error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *apiRPCClient) EnsureBotUser(bot *model.Bot) (string, error) {
|
||||||
|
_args := &Z_EnsureBotUserArgs{bot}
|
||||||
|
_returns := &Z_EnsureBotUserReturns{}
|
||||||
|
if err := g.client.Call("Plugin.EnsureBotUser", _args, _returns); err != nil {
|
||||||
|
log.Printf("RPC call to EnsureBotUser API failed: %s", err.Error())
|
||||||
|
}
|
||||||
|
return _returns.A, _returns.B
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *apiRPCServer) EnsureBotUser(args *Z_EnsureBotUserArgs, returns *Z_EnsureBotUserReturns) error {
|
||||||
|
if hook, ok := s.impl.(interface {
|
||||||
|
EnsureBotUser(bot *model.Bot) (string, error)
|
||||||
|
}); ok {
|
||||||
|
returns.A, returns.B = hook.EnsureBotUser(args.A)
|
||||||
|
returns.B = encodableError(returns.B)
|
||||||
|
} else {
|
||||||
|
return encodableError(fmt.Errorf("API EnsureBotUser called but not implemented."))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -620,6 +620,27 @@ func (_m *API) EnablePlugin(id string) *model.AppError {
|
|||||||
return r0
|
return r0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EnsureBotUser provides a mock function with given fields: bot
|
||||||
|
func (_m *API) EnsureBotUser(bot *model.Bot) (string, error) {
|
||||||
|
ret := _m.Called(bot)
|
||||||
|
|
||||||
|
var r0 string
|
||||||
|
if rf, ok := ret.Get(0).(func(*model.Bot) string); ok {
|
||||||
|
r0 = rf(bot)
|
||||||
|
} else {
|
||||||
|
r0 = ret.Get(0).(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
var r1 error
|
||||||
|
if rf, ok := ret.Get(1).(func(*model.Bot) error); ok {
|
||||||
|
r1 = rf(bot)
|
||||||
|
} else {
|
||||||
|
r1 = ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
// ExecuteSlashCommand provides a mock function with given fields: commandArgs
|
// ExecuteSlashCommand provides a mock function with given fields: commandArgs
|
||||||
func (_m *API) ExecuteSlashCommand(commandArgs *model.CommandArgs) (*model.CommandResponse, error) {
|
func (_m *API) ExecuteSlashCommand(commandArgs *model.CommandArgs) (*model.CommandResponse, error) {
|
||||||
ret := _m.Called(commandArgs)
|
ret := _m.Called(commandArgs)
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user