diff --git a/server/channels/app/bot.go b/server/channels/app/bot.go index 44f3bae84b..22e7d80325 100644 --- a/server/channels/app/bot.go +++ b/server/channels/app/bot.go @@ -33,34 +33,37 @@ func (a *App) EnsureBot(rctx request.CTX, pluginID string, bot *model.Bot) (stri return "", errors.New("passed a bot with no username") } - botIDBytes, err := a.GetPluginKey(pluginID, botUserKey) - if err != nil { - return "", err + botIDBytes, appErr := a.GetPluginKey(pluginID, botUserKey) + if appErr != nil { + return "", appErr } - // If the bot has already been created, use it + // If the bot has already been created, check whether it still exists and use it if botIDBytes != nil { botID := string(botIDBytes) + if _, appErr = a.GetBot(rctx, botID, true); appErr != nil { + rctx.Logger().Debug("Unable to get bot.", mlog.String("bot_id", botID), mlog.Err(appErr)) + } else { + // ensure existing bot is synced with what is being created + botPatch := &model.BotPatch{ + Username: &bot.Username, + DisplayName: &bot.DisplayName, + Description: &bot.Description, + } - // ensure existing bot is synced with what is being created - botPatch := &model.BotPatch{ - Username: &bot.Username, - DisplayName: &bot.DisplayName, - Description: &bot.Description, + if _, appErr = a.PatchBot(rctx, botID, botPatch); appErr != nil { + return "", fmt.Errorf("failed to patch bot: %w", appErr) + } + + return botID, nil } - - if _, err = a.PatchBot(rctx, botID, botPatch); err != nil { - return "", fmt.Errorf("failed to patch bot: %w", err) - } - - return botID, nil } // Check for an existing bot user with that username. If one exists, then use that. if user, appErr := a.GetUserByUsername(bot.Username); appErr == nil && user != nil { if user.IsBot { if appErr := a.SetPluginKey(pluginID, botUserKey, []byte(user.Id)); appErr != nil { - return "", fmt.Errorf("failed to set plugin key: %w", err) + return "", fmt.Errorf("failed to set plugin key: %w", appErr) } } else { rctx.Logger().Error("Plugin attempted to use an account that already exists. Convert user to a bot "+ @@ -82,7 +85,7 @@ func (a *App) EnsureBot(rctx request.CTX, pluginID string, bot *model.Bot) (stri } if appErr := a.SetPluginKey(pluginID, botUserKey, []byte(createdBot.UserId)); appErr != nil { - return "", fmt.Errorf("failed to set plugin key: %w", err) + return "", fmt.Errorf("failed to set plugin key: %w", appErr) } return createdBot.UserId, nil diff --git a/server/channels/app/bot_test.go b/server/channels/app/bot_test.go index 65ad78d7f8..902b5edfbe 100644 --- a/server/channels/app/bot_test.go +++ b/server/channels/app/bot_test.go @@ -112,6 +112,80 @@ func TestCreateBot(t *testing.T) { }) } +func TestEnsureBot(t *testing.T) { + t.Run("ensure bot should pass if already exist bot user", func(t *testing.T) { + th := Setup(t).InitBasic() + defer th.TearDown() + pluginId := "pluginId" + + appErr := th.App.SetPluginKey(pluginId, "key", []byte("test")) + require.Nil(t, appErr) + + botID1, err := th.App.EnsureBot(th.Context, pluginId, &model.Bot{ + Username: "username", + Description: "a bot", + OwnerId: th.BasicUser.Id, + }) + require.NoError(t, err) + + bot, appErr := th.App.GetBot(th.Context, botID1, true) + require.Nil(t, appErr) + assert.Equal(t, "username", bot.Username) + assert.Equal(t, "a bot", bot.Description) + + botID2, err := th.App.EnsureBot(th.Context, pluginId, &model.Bot{ + Username: "another_username", + Description: "another bot", + OwnerId: th.BasicUser.Id, + }) + require.NoError(t, err) + assert.Equal(t, botID1, botID2) + + bot, appErr = th.App.GetBot(th.Context, botID2, true) + require.Nil(t, appErr) + assert.Equal(t, "another_username", bot.Username) + assert.Equal(t, "another bot", bot.Description) + }) + + t.Run("ensure bot should pass even after delete bot user", func(t *testing.T) { + th := Setup(t).InitBasic() + defer th.TearDown() + pluginId := "pluginId" + + appErr := th.App.SetPluginKey(pluginId, "key", []byte("test")) + require.Nil(t, appErr) + + initialBot := model.Bot{ + Username: "username", + Description: "a bot", + OwnerId: th.BasicUser.Id, + } + + botID1, err := th.App.EnsureBot(th.Context, pluginId, &initialBot) + require.NoError(t, err) + + bot, appErr := th.App.GetBot(th.Context, botID1, true) + require.Nil(t, appErr) + assert.Equal(t, "username", bot.Username) + assert.Equal(t, "a bot", bot.Description) + + err = th.App.Srv().Store().User().PermanentDelete(initialBot.UserId) + require.NoError(t, err) + botID2, err := th.App.EnsureBot(th.Context, pluginId, &model.Bot{ + Username: "another_username", + Description: "another bot", + OwnerId: th.BasicUser.Id, + }) + require.NoError(t, err) + assert.NotEqual(t, botID1, botID2) + + bot, appErr = th.App.GetBot(th.Context, botID2, true) + require.Nil(t, appErr) + assert.Equal(t, "another_username", bot.Username) + assert.Equal(t, "another bot", bot.Description) + }) +} + func TestPatchBot(t *testing.T) { t.Run("invalid patch for user", func(t *testing.T) { th := Setup(t).InitBasic()