mirror of
https://github.com/mattermost/mattermost.git
synced 2025-02-25 18:55:24 -06:00
Merge branch 'master' into MM-28014_Improve_Channel_Intros
This commit is contained in:
commit
ce6d6673a6
35
NOTICE.txt
35
NOTICE.txt
@ -12243,6 +12243,41 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
|
||||
---
|
||||
|
||||
## stylelint
|
||||
|
||||
This product contains 'stylelint' by stylelint.
|
||||
|
||||
A mighty CSS linter that helps you avoid errors and enforce conventions.
|
||||
|
||||
* HOMEPAGE:
|
||||
* https://stylelint.io
|
||||
|
||||
* LICENSE: MIT
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 - present Maxime Thirouin, David Clark & Richard Hallows
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
---
|
||||
|
||||
## throttled/throttled
|
||||
|
@ -147,7 +147,7 @@ TEMPLATES_DIR=templates
|
||||
|
||||
# Plugins Packages
|
||||
PLUGIN_PACKAGES ?= $(PLUGIN_PACKAGES:)
|
||||
PLUGIN_PACKAGES += mattermost-plugin-calls-v0.24.0
|
||||
PLUGIN_PACKAGES += mattermost-plugin-calls-v0.25.0
|
||||
PLUGIN_PACKAGES += mattermost-plugin-github-v2.2.0
|
||||
PLUGIN_PACKAGES += mattermost-plugin-gitlab-v1.8.0
|
||||
PLUGIN_PACKAGES += mattermost-plugin-playbooks-v1.39.1
|
||||
|
@ -485,9 +485,9 @@ func (th *TestHelper) InitBasic() *TestHelper {
|
||||
}
|
||||
|
||||
func (th *TestHelper) DeleteBots() *TestHelper {
|
||||
preexistingBots, _ := th.App.GetBots(&model.BotGetOptions{Page: 0, PerPage: 100})
|
||||
preexistingBots, _ := th.App.GetBots(th.Context, &model.BotGetOptions{Page: 0, PerPage: 100})
|
||||
for _, bot := range preexistingBots {
|
||||
th.App.PermanentDeleteBot(bot.UserId)
|
||||
th.App.PermanentDeleteBot(th.Context, bot.UserId)
|
||||
}
|
||||
return th
|
||||
}
|
||||
|
@ -93,7 +93,7 @@ func patchBot(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
audit.AddEventParameter(auditRec, "id", botUserId)
|
||||
audit.AddEventParameterAuditable(auditRec, "bot", botPatch)
|
||||
|
||||
if err := c.App.SessionHasPermissionToManageBot(*c.AppContext.Session(), botUserId); err != nil {
|
||||
if err := c.App.SessionHasPermissionToManageBot(c.AppContext, *c.AppContext.Session(), botUserId); err != nil {
|
||||
c.Err = err
|
||||
return
|
||||
}
|
||||
@ -122,7 +122,7 @@ func getBot(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
includeDeleted, _ := strconv.ParseBool(r.URL.Query().Get("include_deleted"))
|
||||
|
||||
bot, appErr := c.App.GetBot(botUserId, includeDeleted)
|
||||
bot, appErr := c.App.GetBot(c.AppContext, botUserId, includeDeleted)
|
||||
if appErr != nil {
|
||||
c.Err = appErr
|
||||
return
|
||||
@ -170,7 +170,7 @@ func getBots(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
bots, appErr := c.App.GetBots(&model.BotGetOptions{
|
||||
bots, appErr := c.App.GetBots(c.AppContext, &model.BotGetOptions{
|
||||
Page: c.Params.Page,
|
||||
PerPage: c.Params.PerPage,
|
||||
OwnerId: OwnerId,
|
||||
@ -211,7 +211,7 @@ func updateBotActive(c *Context, w http.ResponseWriter, active bool) {
|
||||
audit.AddEventParameter(auditRec, "id", botUserId)
|
||||
audit.AddEventParameter(auditRec, "enable", active)
|
||||
|
||||
if err := c.App.SessionHasPermissionToManageBot(*c.AppContext.Session(), botUserId); err != nil {
|
||||
if err := c.App.SessionHasPermissionToManageBot(c.AppContext, *c.AppContext.Session(), botUserId); err != nil {
|
||||
c.Err = err
|
||||
return
|
||||
}
|
||||
@ -245,7 +245,7 @@ func assignBot(c *Context, w http.ResponseWriter, _ *http.Request) {
|
||||
audit.AddEventParameter(auditRec, "id", botUserId)
|
||||
audit.AddEventParameter(auditRec, "user_id", userId)
|
||||
|
||||
if err := c.App.SessionHasPermissionToManageBot(*c.AppContext.Session(), botUserId); err != nil {
|
||||
if err := c.App.SessionHasPermissionToManageBot(c.AppContext, *c.AppContext.Session(), botUserId); err != nil {
|
||||
c.Err = err
|
||||
return
|
||||
}
|
||||
@ -257,7 +257,7 @@ func assignBot(c *Context, w http.ResponseWriter, _ *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
bot, err := c.App.UpdateBotOwner(botUserId, userId)
|
||||
bot, err := c.App.UpdateBotOwner(c.AppContext, botUserId, userId)
|
||||
if err != nil {
|
||||
c.Err = err
|
||||
return
|
||||
@ -278,7 +278,7 @@ func convertBotToUser(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
bot, err := c.App.GetBot(c.Params.BotUserId, false)
|
||||
bot, err := c.App.GetBot(c.AppContext, c.Params.BotUserId, false)
|
||||
if err != nil {
|
||||
c.Err = err
|
||||
return
|
||||
|
@ -70,7 +70,7 @@ func TestCreateBot(t *testing.T) {
|
||||
createdBot, resp, err := th.Client.CreateBot(context.Background(), bot)
|
||||
require.NoError(t, err)
|
||||
CheckCreatedStatus(t, resp)
|
||||
defer th.App.PermanentDeleteBot(createdBot.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, createdBot.UserId)
|
||||
require.Equal(t, bot.Username, createdBot.Username)
|
||||
require.Equal(t, bot.DisplayName, createdBot.DisplayName)
|
||||
require.Equal(t, bot.Description, createdBot.Description)
|
||||
@ -117,7 +117,7 @@ func TestCreateBot(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
CheckCreatedStatus(t, resp)
|
||||
defer th.App.PermanentDeleteBot(bot.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, bot.UserId)
|
||||
th.App.UpdateUserRoles(th.Context, bot.UserId, model.TeamUserRoleId+" "+model.SystemUserAccessTokenRoleId, false)
|
||||
|
||||
rtoken, _, err := th.Client.CreateUserAccessToken(context.Background(), bot.UserId, "test token")
|
||||
@ -183,7 +183,7 @@ func TestPatchBot(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
CheckCreatedStatus(t, resp)
|
||||
defer th.App.PermanentDeleteBot(createdBot.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, createdBot.UserId)
|
||||
|
||||
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
||||
botPatch := &model.BotPatch{
|
||||
@ -207,7 +207,7 @@ func TestPatchBot(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
CheckCreatedStatus(t, resp)
|
||||
defer th.App.PermanentDeleteBot(createdBotSystemAdmin.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, createdBotSystemAdmin.UserId)
|
||||
|
||||
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
||||
botPatch := &model.BotPatch{
|
||||
@ -241,7 +241,7 @@ func TestPatchBot(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
CheckCreatedStatus(t, resp)
|
||||
defer th.App.PermanentDeleteBot(createdBot.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, createdBot.UserId)
|
||||
|
||||
_, _, err = th.Client.PatchBot(context.Background(), createdBot.UserId, &model.BotPatch{})
|
||||
CheckErrorID(t, err, "store.sql_bot.get.missing.app_error")
|
||||
@ -265,7 +265,7 @@ func TestPatchBot(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
CheckCreatedStatus(t, resp)
|
||||
defer th.App.PermanentDeleteBot(createdBot.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, createdBot.UserId)
|
||||
|
||||
_, _, err = th.Client.PatchBot(context.Background(), createdBot.UserId, &model.BotPatch{})
|
||||
CheckErrorID(t, err, "api.context.permissions.app_error")
|
||||
@ -289,7 +289,7 @@ func TestPatchBot(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
CheckCreatedStatus(t, resp)
|
||||
defer th.App.PermanentDeleteBot(createdBot.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, createdBot.UserId)
|
||||
|
||||
botPatch := &model.BotPatch{
|
||||
Username: sToP(GenerateTestUsername()),
|
||||
@ -340,7 +340,7 @@ func TestPatchBot(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
CheckCreatedStatus(t, resp)
|
||||
defer th.App.PermanentDeleteBot(createdBot.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, createdBot.UserId)
|
||||
|
||||
botPatch := &model.BotPatch{
|
||||
Username: sToP(GenerateTestUsername()),
|
||||
@ -371,7 +371,7 @@ func TestPatchBot(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
CheckCreatedStatus(t, resp)
|
||||
defer th.App.PermanentDeleteBot(createdBot.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, createdBot.UserId)
|
||||
|
||||
botPatch := &model.BotPatch{
|
||||
Username: sToP(GenerateTestUsername()),
|
||||
@ -402,7 +402,7 @@ func TestPatchBot(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
CheckCreatedStatus(t, resp)
|
||||
defer th.App.PermanentDeleteBot(createdBot.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, createdBot.UserId)
|
||||
|
||||
botPatch := &model.BotPatch{
|
||||
Username: sToP(GenerateTestUsername()),
|
||||
@ -440,7 +440,7 @@ func TestPatchBot(t *testing.T) {
|
||||
createdBot, resp, err := th.Client.CreateBot(context.Background(), bot)
|
||||
require.NoError(t, err)
|
||||
CheckCreatedStatus(t, resp)
|
||||
defer th.App.PermanentDeleteBot(createdBot.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, createdBot.UserId)
|
||||
|
||||
botPatch := &model.BotPatch{
|
||||
Username: sToP(GenerateTestUsername()),
|
||||
@ -474,7 +474,7 @@ func TestPatchBot(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
CheckCreatedStatus(t, resp)
|
||||
defer th.App.PermanentDeleteBot(createdBot.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, createdBot.UserId)
|
||||
|
||||
r, err := th.Client.DoAPIPut(context.Background(), "/bots/"+createdBot.UserId, `{"creator_id":"`+th.BasicUser2.Id+`"}`)
|
||||
require.NoError(t, err)
|
||||
@ -511,7 +511,7 @@ func TestPatchBot(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
CheckCreatedStatus(t, resp)
|
||||
defer th.App.PermanentDeleteBot(createdBot.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, createdBot.UserId)
|
||||
|
||||
var botPatch *model.BotPatch
|
||||
|
||||
@ -536,7 +536,7 @@ func TestGetBot(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
CheckCreatedStatus(t, resp)
|
||||
defer th.App.PermanentDeleteBot(bot1.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, bot1.UserId)
|
||||
|
||||
bot2, resp, err := th.SystemAdminClient.CreateBot(context.Background(), &model.Bot{
|
||||
Username: GenerateTestUsername(),
|
||||
@ -545,7 +545,7 @@ func TestGetBot(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
CheckCreatedStatus(t, resp)
|
||||
defer th.App.PermanentDeleteBot(bot2.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, bot2.UserId)
|
||||
|
||||
deletedBot, resp, err := th.SystemAdminClient.CreateBot(context.Background(), &model.Bot{
|
||||
Username: GenerateTestUsername(),
|
||||
@ -553,7 +553,7 @@ func TestGetBot(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
CheckCreatedStatus(t, resp)
|
||||
defer th.App.PermanentDeleteBot(deletedBot.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, deletedBot.UserId)
|
||||
deletedBot, resp, err = th.SystemAdminClient.DisableBot(context.Background(), deletedBot.UserId)
|
||||
require.NoError(t, err)
|
||||
CheckOKStatus(t, resp)
|
||||
@ -571,7 +571,7 @@ func TestGetBot(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
CheckCreatedStatus(t, resp)
|
||||
defer th.App.PermanentDeleteBot(myBot.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, myBot.UserId)
|
||||
th.RemovePermissionFromRole(model.PermissionCreateBot.Id, model.TeamUserRoleId)
|
||||
|
||||
t.Run("get unknown bot", func(t *testing.T) {
|
||||
@ -690,7 +690,7 @@ func TestGetBots(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
CheckCreatedStatus(t, resp)
|
||||
defer th.App.PermanentDeleteBot(bot1.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, bot1.UserId)
|
||||
|
||||
deletedBot1, resp, err := th.SystemAdminClient.CreateBot(context.Background(), &model.Bot{
|
||||
Username: GenerateTestUsername(),
|
||||
@ -698,7 +698,7 @@ func TestGetBots(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
CheckCreatedStatus(t, resp)
|
||||
defer th.App.PermanentDeleteBot(deletedBot1.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, deletedBot1.UserId)
|
||||
deletedBot1, resp, err = th.SystemAdminClient.DisableBot(context.Background(), deletedBot1.UserId)
|
||||
require.NoError(t, err)
|
||||
CheckOKStatus(t, resp)
|
||||
@ -710,7 +710,7 @@ func TestGetBots(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
CheckCreatedStatus(t, resp)
|
||||
defer th.App.PermanentDeleteBot(bot2.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, bot2.UserId)
|
||||
|
||||
bot3, resp, err := th.SystemAdminClient.CreateBot(context.Background(), &model.Bot{
|
||||
Username: GenerateTestUsername(),
|
||||
@ -719,7 +719,7 @@ func TestGetBots(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
CheckCreatedStatus(t, resp)
|
||||
defer th.App.PermanentDeleteBot(bot3.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, bot3.UserId)
|
||||
|
||||
deletedBot2, resp, err := th.SystemAdminClient.CreateBot(context.Background(), &model.Bot{
|
||||
Username: GenerateTestUsername(),
|
||||
@ -727,7 +727,7 @@ func TestGetBots(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
CheckCreatedStatus(t, resp)
|
||||
defer th.App.PermanentDeleteBot(deletedBot2.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, deletedBot2.UserId)
|
||||
deletedBot2, resp, err = th.SystemAdminClient.DisableBot(context.Background(), deletedBot2.UserId)
|
||||
require.NoError(t, err)
|
||||
CheckOKStatus(t, resp)
|
||||
@ -742,7 +742,7 @@ func TestGetBots(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
CheckCreatedStatus(t, resp)
|
||||
th.LoginBasic()
|
||||
defer th.App.PermanentDeleteBot(orphanedBot.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, orphanedBot.UserId)
|
||||
// Automatic deactivation disabled
|
||||
th.App.UpdateConfig(func(cfg *model.Config) {
|
||||
*cfg.ServiceSettings.DisableBotsWhenOwnerIsDeactivated = false
|
||||
@ -975,7 +975,7 @@ func TestDisableBot(t *testing.T) {
|
||||
createdBot, resp, err := th.Client.CreateBot(context.Background(), bot)
|
||||
require.NoError(t, err)
|
||||
CheckCreatedStatus(t, resp)
|
||||
defer th.App.PermanentDeleteBot(createdBot.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, createdBot.UserId)
|
||||
|
||||
_, _, err = th.Client.DisableBot(context.Background(), createdBot.UserId)
|
||||
CheckErrorID(t, err, "store.sql_bot.get.missing.app_error")
|
||||
@ -1001,7 +1001,7 @@ func TestDisableBot(t *testing.T) {
|
||||
createdBot, resp, err := th.Client.CreateBot(context.Background(), bot)
|
||||
require.NoError(t, err)
|
||||
CheckCreatedStatus(t, resp)
|
||||
defer th.App.PermanentDeleteBot(createdBot.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, createdBot.UserId)
|
||||
|
||||
_, _, err = th.Client.DisableBot(context.Background(), createdBot.UserId)
|
||||
CheckErrorID(t, err, "api.context.permissions.app_error")
|
||||
@ -1026,7 +1026,7 @@ func TestDisableBot(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
CheckCreatedStatus(t, resp)
|
||||
defer th.App.PermanentDeleteBot(bot.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, bot.UserId)
|
||||
|
||||
disabledBot, resp, err := client.DisableBot(context.Background(), bot.UserId)
|
||||
require.NoError(t, err)
|
||||
@ -1080,7 +1080,7 @@ func TestEnableBot(t *testing.T) {
|
||||
createdBot, resp, err := th.Client.CreateBot(context.Background(), bot)
|
||||
require.NoError(t, err)
|
||||
CheckCreatedStatus(t, resp)
|
||||
defer th.App.PermanentDeleteBot(createdBot.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, createdBot.UserId)
|
||||
|
||||
_, resp, err = th.SystemAdminClient.DisableBot(context.Background(), createdBot.UserId)
|
||||
require.NoError(t, err)
|
||||
@ -1110,7 +1110,7 @@ func TestEnableBot(t *testing.T) {
|
||||
createdBot, resp, err := th.Client.CreateBot(context.Background(), bot)
|
||||
require.NoError(t, err)
|
||||
CheckCreatedStatus(t, resp)
|
||||
defer th.App.PermanentDeleteBot(createdBot.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, createdBot.UserId)
|
||||
|
||||
_, resp, err = th.SystemAdminClient.DisableBot(context.Background(), createdBot.UserId)
|
||||
require.NoError(t, err)
|
||||
@ -1139,7 +1139,7 @@ func TestEnableBot(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
CheckCreatedStatus(t, resp)
|
||||
defer th.App.PermanentDeleteBot(bot.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, bot.UserId)
|
||||
|
||||
_, resp, err = th.SystemAdminClient.DisableBot(context.Background(), bot.UserId)
|
||||
require.NoError(t, err)
|
||||
@ -1195,7 +1195,7 @@ func TestAssignBot(t *testing.T) {
|
||||
bot, resp, err := th.Client.CreateBot(context.Background(), bot)
|
||||
require.NoError(t, err)
|
||||
CheckCreatedStatus(t, resp)
|
||||
defer th.App.PermanentDeleteBot(bot.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, bot.UserId)
|
||||
|
||||
before, resp, err := th.Client.GetBot(context.Background(), bot.UserId, "")
|
||||
require.NoError(t, err)
|
||||
@ -1244,7 +1244,7 @@ func TestAssignBot(t *testing.T) {
|
||||
createdBot, resp, err := th.Client.CreateBot(context.Background(), bot)
|
||||
require.NoError(t, err)
|
||||
CheckCreatedStatus(t, resp)
|
||||
defer th.App.PermanentDeleteBot(createdBot.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, createdBot.UserId)
|
||||
|
||||
th.LoginBasic2()
|
||||
|
||||
@ -1276,7 +1276,7 @@ func TestAssignBot(t *testing.T) {
|
||||
bot, resp, err := th.Client.CreateBot(context.Background(), bot)
|
||||
require.NoError(t, err)
|
||||
CheckCreatedStatus(t, resp)
|
||||
defer th.App.PermanentDeleteBot(bot.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, bot.UserId)
|
||||
|
||||
// Simulate custom role by just changing the system user role
|
||||
th.AddPermissionToRole(model.PermissionCreateBot.Id, model.SystemUserRoleId)
|
||||
@ -1312,7 +1312,7 @@ func TestAssignBot(t *testing.T) {
|
||||
bot, resp, err := th.Client.CreateBot(context.Background(), bot)
|
||||
require.NoError(t, err)
|
||||
CheckCreatedStatus(t, resp)
|
||||
defer th.App.PermanentDeleteBot(bot.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, bot.UserId)
|
||||
|
||||
bot2, resp, err := th.Client.CreateBot(context.Background(), &model.Bot{
|
||||
Username: GenerateTestUsername(),
|
||||
@ -1321,7 +1321,7 @@ func TestAssignBot(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
CheckCreatedStatus(t, resp)
|
||||
defer th.App.PermanentDeleteBot(bot2.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, bot2.UserId)
|
||||
|
||||
_, _, err = th.Client.AssignBot(context.Background(), bot.UserId, bot2.UserId)
|
||||
CheckErrorID(t, err, "api.context.permissions.app_error")
|
||||
@ -1345,7 +1345,7 @@ func TestConvertBotToUser(t *testing.T) {
|
||||
bot, resp, err := th.Client.CreateBot(context.Background(), bot)
|
||||
require.NoError(t, err)
|
||||
CheckCreatedStatus(t, resp)
|
||||
defer th.App.PermanentDeleteBot(bot.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, bot.UserId)
|
||||
|
||||
_, resp, err = th.Client.ConvertBotToUser(context.Background(), bot.UserId, &model.UserPatch{}, false)
|
||||
require.Error(t, err)
|
||||
|
@ -463,7 +463,7 @@ func getAnalytics(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
rows, appErr := c.App.GetAnalytics(name, teamId)
|
||||
rows, appErr := c.App.GetAnalytics(c.AppContext, name, teamId)
|
||||
if appErr != nil {
|
||||
c.Err = appErr
|
||||
return
|
||||
|
@ -430,7 +430,7 @@ func setProfileImage(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if !c.App.SessionHasPermissionToUserOrBot(*c.AppContext.Session(), c.Params.UserId) {
|
||||
if !c.App.SessionHasPermissionToUserOrBot(c.AppContext, *c.AppContext.Session(), c.Params.UserId) {
|
||||
c.SetPermissionError(model.PermissionEditOtherUsers)
|
||||
return
|
||||
}
|
||||
@ -501,7 +501,7 @@ func setDefaultProfileImage(c *Context, w http.ResponseWriter, r *http.Request)
|
||||
return
|
||||
}
|
||||
|
||||
if !c.App.SessionHasPermissionToUserOrBot(*c.AppContext.Session(), c.Params.UserId) {
|
||||
if !c.App.SessionHasPermissionToUserOrBot(c.AppContext, *c.AppContext.Session(), c.Params.UserId) {
|
||||
c.SetPermissionError(model.PermissionEditOtherUsers)
|
||||
return
|
||||
}
|
||||
@ -851,9 +851,9 @@ func getUsers(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
if sort == "last_activity_at" {
|
||||
profiles, appErr = c.App.GetRecentlyActiveUsersForTeamPage(inTeamId, c.Params.Page, c.Params.PerPage, c.IsSystemAdmin(), restrictions)
|
||||
profiles, appErr = c.App.GetRecentlyActiveUsersForTeamPage(c.AppContext, inTeamId, c.Params.Page, c.Params.PerPage, c.IsSystemAdmin(), restrictions)
|
||||
} else if sort == "create_at" {
|
||||
profiles, appErr = c.App.GetNewUsersForTeamPage(inTeamId, c.Params.Page, c.Params.PerPage, c.IsSystemAdmin(), restrictions)
|
||||
profiles, appErr = c.App.GetNewUsersForTeamPage(c.AppContext, inTeamId, c.Params.Page, c.Params.PerPage, c.IsSystemAdmin(), restrictions)
|
||||
} else {
|
||||
etag = c.App.GetUsersInTeamEtag(inTeamId, restrictions.Hash())
|
||||
if c.HandleEtag(etag, "Get Users in Team", w, r) {
|
||||
@ -1260,7 +1260,7 @@ func updateUser(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if !c.App.SessionHasPermissionToUserOrBot(*c.AppContext.Session(), user.Id) {
|
||||
if !c.App.SessionHasPermissionToUserOrBot(c.AppContext, *c.AppContext.Session(), user.Id) {
|
||||
c.SetPermissionError(model.PermissionEditOtherUsers)
|
||||
return
|
||||
}
|
||||
@ -1337,7 +1337,7 @@ func patchUser(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
audit.AddEventParameterAuditable(auditRec, "user_patch", &patch)
|
||||
defer c.LogAuditRec(auditRec)
|
||||
|
||||
if !c.App.SessionHasPermissionToUserOrBot(*c.AppContext.Session(), c.Params.UserId) {
|
||||
if !c.App.SessionHasPermissionToUserOrBot(c.AppContext, *c.AppContext.Session(), c.Params.UserId) {
|
||||
c.SetPermissionError(model.PermissionEditOtherUsers)
|
||||
return
|
||||
}
|
||||
@ -1417,7 +1417,7 @@ func deleteUser(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
audit.AddEventParameter(auditRec, "permanent", permanent)
|
||||
defer c.LogAuditRec(auditRec)
|
||||
|
||||
if !c.App.SessionHasPermissionToUserOrBot(*c.AppContext.Session(), userId) {
|
||||
if !c.App.SessionHasPermissionToUserOrBot(c.AppContext, *c.AppContext.Session(), userId) {
|
||||
c.SetPermissionError(model.PermissionEditOtherUsers)
|
||||
return
|
||||
}
|
||||
@ -2458,7 +2458,7 @@ func createUserAccessToken(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if !c.App.SessionHasPermissionToUserOrBot(*c.AppContext.Session(), c.Params.UserId) {
|
||||
if !c.App.SessionHasPermissionToUserOrBot(c.AppContext, *c.AppContext.Session(), c.Params.UserId) {
|
||||
c.SetPermissionError(model.PermissionEditOtherUsers)
|
||||
return
|
||||
}
|
||||
@ -2550,7 +2550,7 @@ func getUserAccessTokensForUser(c *Context, w http.ResponseWriter, r *http.Reque
|
||||
return
|
||||
}
|
||||
|
||||
if !c.App.SessionHasPermissionToUserOrBot(*c.AppContext.Session(), c.Params.UserId) {
|
||||
if !c.App.SessionHasPermissionToUserOrBot(c.AppContext, *c.AppContext.Session(), c.Params.UserId) {
|
||||
c.SetPermissionError(model.PermissionEditOtherUsers)
|
||||
return
|
||||
}
|
||||
@ -2587,7 +2587,7 @@ func getUserAccessToken(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if !c.App.SessionHasPermissionToUserOrBot(*c.AppContext.Session(), accessToken.UserId) {
|
||||
if !c.App.SessionHasPermissionToUserOrBot(c.AppContext, *c.AppContext.Session(), accessToken.UserId) {
|
||||
c.SetPermissionError(model.PermissionEditOtherUsers)
|
||||
return
|
||||
}
|
||||
@ -2625,7 +2625,7 @@ func revokeUserAccessToken(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
audit.AddEventParameterAuditable(auditRec, "user", user)
|
||||
}
|
||||
|
||||
if !c.App.SessionHasPermissionToUserOrBot(*c.AppContext.Session(), accessToken.UserId) {
|
||||
if !c.App.SessionHasPermissionToUserOrBot(c.AppContext, *c.AppContext.Session(), accessToken.UserId) {
|
||||
c.SetPermissionError(model.PermissionEditOtherUsers)
|
||||
return
|
||||
}
|
||||
@ -2670,7 +2670,7 @@ func disableUserAccessToken(c *Context, w http.ResponseWriter, r *http.Request)
|
||||
audit.AddEventParameterAuditable(auditRec, "user", user)
|
||||
}
|
||||
|
||||
if !c.App.SessionHasPermissionToUserOrBot(*c.AppContext.Session(), accessToken.UserId) {
|
||||
if !c.App.SessionHasPermissionToUserOrBot(c.AppContext, *c.AppContext.Session(), accessToken.UserId) {
|
||||
c.SetPermissionError(model.PermissionEditOtherUsers)
|
||||
return
|
||||
}
|
||||
@ -2715,7 +2715,7 @@ func enableUserAccessToken(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
audit.AddEventParameterAuditable(auditRec, "user", user)
|
||||
}
|
||||
|
||||
if !c.App.SessionHasPermissionToUserOrBot(*c.AppContext.Session(), accessToken.UserId) {
|
||||
if !c.App.SessionHasPermissionToUserOrBot(c.AppContext, *c.AppContext.Session(), accessToken.UserId) {
|
||||
c.SetPermissionError(model.PermissionEditOtherUsers)
|
||||
return
|
||||
}
|
||||
@ -2965,7 +2965,7 @@ func convertUserToBot(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
bot, appErr := c.App.ConvertUserToBot(user)
|
||||
bot, appErr := c.App.ConvertUserToBot(c.AppContext, user)
|
||||
if appErr != nil {
|
||||
c.Err = appErr
|
||||
return
|
||||
|
@ -194,9 +194,9 @@ func localGetUsers(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
profiles, appErr = c.App.GetUsersNotInTeamPage(notInTeamId, groupConstrainedBool, c.Params.Page, c.Params.PerPage, c.IsSystemAdmin(), nil)
|
||||
} else if inTeamId != "" {
|
||||
if sort == "last_activity_at" {
|
||||
profiles, appErr = c.App.GetRecentlyActiveUsersForTeamPage(inTeamId, c.Params.Page, c.Params.PerPage, c.IsSystemAdmin(), nil)
|
||||
profiles, appErr = c.App.GetRecentlyActiveUsersForTeamPage(c.AppContext, c.Params.TeamId, c.Params.Page, c.Params.PerPage, c.IsSystemAdmin(), nil)
|
||||
} else if sort == "create_at" {
|
||||
profiles, appErr = c.App.GetNewUsersForTeamPage(inTeamId, c.Params.Page, c.Params.PerPage, c.IsSystemAdmin(), nil)
|
||||
profiles, appErr = c.App.GetNewUsersForTeamPage(c.AppContext, c.Params.TeamId, c.Params.Page, c.Params.PerPage, c.IsSystemAdmin(), nil)
|
||||
} else {
|
||||
etag = c.App.GetUsersInTeamEtag(inTeamId, "")
|
||||
if c.HandleEtag(etag, "Get Users in Team", w, r) {
|
||||
|
@ -916,7 +916,7 @@ func TestGetBotUser(t *testing.T) {
|
||||
createdBot, resp, err := th.Client.CreateBot(context.Background(), bot)
|
||||
require.NoError(t, err)
|
||||
CheckCreatedStatus(t, resp)
|
||||
defer th.App.PermanentDeleteBot(createdBot.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, createdBot.UserId)
|
||||
|
||||
botUser, _, err := th.Client.GetUser(context.Background(), createdBot.UserId, "")
|
||||
require.NoError(t, err)
|
||||
@ -4556,7 +4556,7 @@ func TestCreateUserAccessToken(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
CheckCreatedStatus(t, resp)
|
||||
defer th.App.PermanentDeleteBot(createdBot.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, createdBot.UserId)
|
||||
|
||||
t.Run("without MANAGE_BOT permission", func(t *testing.T) {
|
||||
th.RemovePermissionFromRole(model.PermissionManageBots.Id, model.TeamUserRoleId)
|
||||
@ -4598,7 +4598,7 @@ func TestCreateUserAccessToken(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
CheckCreatedStatus(t, resp)
|
||||
defer th.App.PermanentDeleteBot(createdBot.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, createdBot.UserId)
|
||||
|
||||
t.Run("only having MANAGE_BOTS permission", func(t *testing.T) {
|
||||
_, resp, err = th.Client.CreateUserAccessToken(context.Background(), createdBot.UserId, "test token")
|
||||
@ -4703,7 +4703,7 @@ func TestGetUserAccessToken(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
CheckCreatedStatus(t, resp)
|
||||
defer th.App.PermanentDeleteBot(createdBot.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, createdBot.UserId)
|
||||
|
||||
token, _, err := th.Client.CreateUserAccessToken(context.Background(), createdBot.UserId, "test token")
|
||||
require.NoError(t, err)
|
||||
@ -4751,7 +4751,7 @@ func TestGetUserAccessToken(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
CheckCreatedStatus(t, resp)
|
||||
defer th.App.PermanentDeleteBot(createdBot.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, createdBot.UserId)
|
||||
|
||||
token, _, err := th.SystemAdminClient.CreateUserAccessToken(context.Background(), createdBot.UserId, "test token")
|
||||
require.NoError(t, err)
|
||||
@ -4976,7 +4976,7 @@ func TestRevokeUserAccessToken(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
CheckCreatedStatus(t, resp)
|
||||
defer th.App.PermanentDeleteBot(createdBot.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, createdBot.UserId)
|
||||
|
||||
token, _, err := th.Client.CreateUserAccessToken(context.Background(), createdBot.UserId, "test token")
|
||||
require.NoError(t, err)
|
||||
@ -5020,7 +5020,7 @@ func TestRevokeUserAccessToken(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
CheckCreatedStatus(t, resp)
|
||||
defer th.App.PermanentDeleteBot(createdBot.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, createdBot.UserId)
|
||||
|
||||
token, _, err := th.SystemAdminClient.CreateUserAccessToken(context.Background(), createdBot.UserId, "test token")
|
||||
require.NoError(t, err)
|
||||
@ -5095,7 +5095,7 @@ func TestDisableUserAccessToken(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
CheckCreatedStatus(t, resp)
|
||||
defer th.App.PermanentDeleteBot(createdBot.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, createdBot.UserId)
|
||||
|
||||
token, _, err := th.Client.CreateUserAccessToken(context.Background(), createdBot.UserId, "test token")
|
||||
require.NoError(t, err)
|
||||
@ -5139,7 +5139,7 @@ func TestDisableUserAccessToken(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
CheckCreatedStatus(t, resp)
|
||||
defer th.App.PermanentDeleteBot(createdBot.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, createdBot.UserId)
|
||||
|
||||
token, _, err := th.SystemAdminClient.CreateUserAccessToken(context.Background(), createdBot.UserId, "test token")
|
||||
require.NoError(t, err)
|
||||
@ -5222,7 +5222,7 @@ func TestEnableUserAccessToken(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
CheckCreatedStatus(t, resp)
|
||||
defer th.App.PermanentDeleteBot(createdBot.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, createdBot.UserId)
|
||||
|
||||
token, _, err := th.Client.CreateUserAccessToken(context.Background(), createdBot.UserId, "test token")
|
||||
require.NoError(t, err)
|
||||
@ -5269,7 +5269,7 @@ func TestEnableUserAccessToken(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
CheckCreatedStatus(t, resp)
|
||||
defer th.App.PermanentDeleteBot(createdBot.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, createdBot.UserId)
|
||||
|
||||
token, _, err := th.SystemAdminClient.CreateUserAccessToken(context.Background(), createdBot.UserId, "test token")
|
||||
require.NoError(t, err)
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
|
||||
"github.com/mattermost/mattermost/server/public/model"
|
||||
"github.com/mattermost/mattermost/server/public/shared/mlog"
|
||||
"github.com/mattermost/mattermost/server/public/shared/request"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -17,7 +18,7 @@ const (
|
||||
MonthMilliseconds = 31 * DayMilliseconds
|
||||
)
|
||||
|
||||
func (a *App) GetAnalytics(name string, teamID string) (model.AnalyticsRows, *model.AppError) {
|
||||
func (a *App) GetAnalytics(rctx request.CTX, name string, teamID string) (model.AnalyticsRows, *model.AppError) {
|
||||
skipIntensiveQueries := false
|
||||
var systemUserCount int64
|
||||
systemUserCount, err := a.Srv().Store().User().Count(model.UserCountOptions{})
|
||||
@ -26,7 +27,7 @@ func (a *App) GetAnalytics(name string, teamID string) (model.AnalyticsRows, *mo
|
||||
}
|
||||
|
||||
if systemUserCount > int64(*a.Config().AnalyticsSettings.MaxUsersForStatistics) {
|
||||
mlog.Debug("More than limit users are on the system, intensive queries skipped", mlog.Int("limit", *a.Config().AnalyticsSettings.MaxUsersForStatistics))
|
||||
rctx.Logger().Debug("More than limit users are on the system, intensive queries skipped", mlog.Int("limit", *a.Config().AnalyticsSettings.MaxUsersForStatistics))
|
||||
skipIntensiveQueries = true
|
||||
}
|
||||
|
||||
@ -306,7 +307,7 @@ func (a *App) GetAnalytics(name string, teamID string) (model.AnalyticsRows, *mo
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (a *App) GetRecentlyActiveUsersForTeam(teamID string) (map[string]*model.User, *model.AppError) {
|
||||
func (a *App) GetRecentlyActiveUsersForTeam(rctx request.CTX, teamID string) (map[string]*model.User, *model.AppError) {
|
||||
users, err := a.Srv().Store().User().GetRecentlyActiveUsersForTeam(teamID, 0, 100, nil)
|
||||
if err != nil {
|
||||
return nil, model.NewAppError("GetRecentlyActiveUsersForTeam", "app.user.get_recently_active_users.app_error", nil, "", http.StatusInternalServerError).Wrap(err)
|
||||
@ -321,7 +322,7 @@ func (a *App) GetRecentlyActiveUsersForTeam(teamID string) (map[string]*model.Us
|
||||
return userMap, nil
|
||||
}
|
||||
|
||||
func (a *App) GetRecentlyActiveUsersForTeamPage(teamID string, page, perPage int, asAdmin bool, viewRestrictions *model.ViewUsersRestrictions) ([]*model.User, *model.AppError) {
|
||||
func (a *App) GetRecentlyActiveUsersForTeamPage(rctx request.CTX, teamID string, page, perPage int, asAdmin bool, viewRestrictions *model.ViewUsersRestrictions) ([]*model.User, *model.AppError) {
|
||||
users, err := a.Srv().Store().User().GetRecentlyActiveUsersForTeam(teamID, page*perPage, perPage, viewRestrictions)
|
||||
if err != nil {
|
||||
return nil, model.NewAppError("GetRecentlyActiveUsersForTeamPage", "app.user.get_recently_active_users.app_error", nil, "", http.StatusInternalServerError).Wrap(err)
|
||||
@ -330,7 +331,7 @@ func (a *App) GetRecentlyActiveUsersForTeamPage(teamID string, page, perPage int
|
||||
return a.sanitizeProfiles(users, asAdmin), nil
|
||||
}
|
||||
|
||||
func (a *App) GetNewUsersForTeamPage(teamID string, page, perPage int, asAdmin bool, viewRestrictions *model.ViewUsersRestrictions) ([]*model.User, *model.AppError) {
|
||||
func (a *App) GetNewUsersForTeamPage(rctx request.CTX, teamID string, page, perPage int, asAdmin bool, viewRestrictions *model.ViewUsersRestrictions) ([]*model.User, *model.AppError) {
|
||||
users, err := a.Srv().Store().User().GetNewUsersForTeam(teamID, page*perPage, perPage, viewRestrictions)
|
||||
if err != nil {
|
||||
return nil, model.NewAppError("GetNewUsersForTeamPage", "app.user.get_new_users.app_error", nil, "", http.StatusInternalServerError).Wrap(err)
|
||||
|
@ -86,11 +86,11 @@ type AppIface interface {
|
||||
// ConvertBotToUser converts a bot to user.
|
||||
ConvertBotToUser(c request.CTX, bot *model.Bot, userPatch *model.UserPatch, sysadmin bool) (*model.User, *model.AppError)
|
||||
// ConvertUserToBot converts a user to bot.
|
||||
ConvertUserToBot(user *model.User) (*model.Bot, *model.AppError)
|
||||
ConvertUserToBot(rctx request.CTX, user *model.User) (*model.Bot, *model.AppError)
|
||||
// Create/ Update a subscription history event
|
||||
SendSubscriptionHistoryEvent(userID string) (*model.SubscriptionHistory, error)
|
||||
// CreateBot creates the given bot and corresponding user.
|
||||
CreateBot(c request.CTX, bot *model.Bot) (*model.Bot, *model.AppError)
|
||||
CreateBot(rctx request.CTX, bot *model.Bot) (*model.Bot, *model.AppError)
|
||||
// CreateChannelScheme creates a new Scheme of scope channel and assigns it to the channel.
|
||||
CreateChannelScheme(c request.CTX, channel *model.Channel) (*model.Scheme, *model.AppError)
|
||||
// CreateDefaultMemberships adds users to teams and channels based on their group memberships and how those groups
|
||||
@ -165,9 +165,9 @@ type AppIface interface {
|
||||
// filter.
|
||||
GetAllLdapGroupsPage(rctx request.CTX, page int, perPage int, opts model.LdapGroupSearchOpts) ([]*model.Group, int, *model.AppError)
|
||||
// GetBot returns the given bot.
|
||||
GetBot(botUserId string, includeDeleted bool) (*model.Bot, *model.AppError)
|
||||
GetBot(rctx request.CTX, botUserId string, includeDeleted bool) (*model.Bot, *model.AppError)
|
||||
// GetBots returns the requested page of bots.
|
||||
GetBots(options *model.BotGetOptions) (model.BotList, *model.AppError)
|
||||
GetBots(rctx request.CTX, options *model.BotGetOptions) (model.BotList, *model.AppError)
|
||||
// GetChannelGroupUsers returns the users who are associated to the channel via GroupChannels and GroupMembers.
|
||||
GetChannelGroupUsers(channelID string) ([]*model.User, *model.AppError)
|
||||
// GetChannelModerationsForChannel Gets a channels ChannelModerations from either the higherScoped roles or from the channel scheme roles.
|
||||
@ -293,7 +293,7 @@ type AppIface interface {
|
||||
// For internal requests, requests are routed directly to a plugin ServerHTTP hook
|
||||
DoActionRequest(c request.CTX, rawURL string, body []byte) (*http.Response, *model.AppError)
|
||||
// PermanentDeleteBot permanently deletes a bot and its corresponding user.
|
||||
PermanentDeleteBot(botUserId string) *model.AppError
|
||||
PermanentDeleteBot(rctx request.CTX, botUserId string) *model.AppError
|
||||
// PopulateWebConnConfig checks if the connection id already exists in the hub,
|
||||
// and if so, accordingly populates the other fields of the webconn.
|
||||
PopulateWebConnConfig(s *model.Session, cfg *platform.WebConnConfig, seqVal string) (*platform.WebConnConfig, error)
|
||||
@ -325,7 +325,7 @@ type AppIface interface {
|
||||
// SessionHasPermissionToManageBot returns nil if the session has access to manage the given bot.
|
||||
// This function deviates from other authorization checks in returning an error instead of just
|
||||
// a boolean, allowing the permission failure to be exposed with more granularity.
|
||||
SessionHasPermissionToManageBot(session model.Session, botUserId string) *model.AppError
|
||||
SessionHasPermissionToManageBot(rctx request.CTX, session model.Session, botUserId string) *model.AppError
|
||||
// SessionHasPermissionToTeams returns true only if user has access to all teams.
|
||||
SessionHasPermissionToTeams(c request.CTX, session model.Session, teamIDs []string, permission *model.Permission) bool
|
||||
// SessionIsRegistered determines if a specific session has been registered
|
||||
@ -378,9 +378,9 @@ type AppIface interface {
|
||||
// This to be used for places we check the users password when they are already logged in
|
||||
DoubleCheckPassword(rctx request.CTX, user *model.User, password string) *model.AppError
|
||||
// UpdateBotActive marks a bot as active or inactive, along with its corresponding user.
|
||||
UpdateBotActive(c request.CTX, botUserId string, active bool) (*model.Bot, *model.AppError)
|
||||
UpdateBotActive(rctx request.CTX, botUserId string, active bool) (*model.Bot, *model.AppError)
|
||||
// UpdateBotOwner changes a bot's owner to the given value.
|
||||
UpdateBotOwner(botUserId, newOwnerId string) (*model.Bot, *model.AppError)
|
||||
UpdateBotOwner(rctx request.CTX, botUserId, newOwnerId string) (*model.Bot, *model.AppError)
|
||||
// UpdateChannel updates a given channel by its Id. It also publishes the CHANNEL_UPDATED event.
|
||||
UpdateChannel(c request.CTX, channel *model.Channel) (*model.Channel, *model.AppError)
|
||||
// UpdateChannelScheme saves the new SchemeId of the channel passed.
|
||||
@ -621,7 +621,7 @@ type AppIface interface {
|
||||
GetAllTeams() ([]*model.Team, *model.AppError)
|
||||
GetAllTeamsPage(offset int, limit int, opts *model.TeamSearch) ([]*model.Team, *model.AppError)
|
||||
GetAllTeamsPageWithCount(offset int, limit int, opts *model.TeamSearch) (*model.TeamsWithCount, *model.AppError)
|
||||
GetAnalytics(name string, teamID string) (model.AnalyticsRows, *model.AppError)
|
||||
GetAnalytics(rctx request.CTX, name string, teamID string) (model.AnalyticsRows, *model.AppError)
|
||||
GetAppliedSchemaMigrations() ([]model.AppliedMigration, *model.AppError)
|
||||
GetAudits(rctx request.CTX, userID string, limit int) (model.Audits, *model.AppError)
|
||||
GetAuditsPage(rctx request.CTX, userID string, page int, perPage int) (model.Audits, *model.AppError)
|
||||
@ -717,7 +717,7 @@ type AppIface interface {
|
||||
GetMemberCountsByGroup(rctx request.CTX, channelID string, includeTimezones bool) ([]*model.ChannelMemberCountByGroup, *model.AppError)
|
||||
GetMessageForNotification(post *model.Post, teamName, siteUrl string, translateFunc i18n.TranslateFunc) string
|
||||
GetMultipleEmojiByName(c request.CTX, names []string) ([]*model.Emoji, *model.AppError)
|
||||
GetNewUsersForTeamPage(teamID string, page, perPage int, asAdmin bool, viewRestrictions *model.ViewUsersRestrictions) ([]*model.User, *model.AppError)
|
||||
GetNewUsersForTeamPage(rctx request.CTX, teamID string, page, perPage int, asAdmin bool, viewRestrictions *model.ViewUsersRestrictions) ([]*model.User, *model.AppError)
|
||||
GetNextPostIdFromPostList(postList *model.PostList, collapsedThreads bool) string
|
||||
GetNotificationNameFormat(user *model.User) string
|
||||
GetNumberOfChannelsOnTeam(c request.CTX, teamID string) (int, *model.AppError)
|
||||
@ -771,8 +771,8 @@ type AppIface interface {
|
||||
GetPublicChannelsByIdsForTeam(c request.CTX, teamID string, channelIDs []string) (model.ChannelList, *model.AppError)
|
||||
GetPublicChannelsForTeam(c request.CTX, teamID string, offset int, limit int) (model.ChannelList, *model.AppError)
|
||||
GetReactionsForPost(postID string) ([]*model.Reaction, *model.AppError)
|
||||
GetRecentlyActiveUsersForTeam(teamID string) (map[string]*model.User, *model.AppError)
|
||||
GetRecentlyActiveUsersForTeamPage(teamID string, page, perPage int, asAdmin bool, viewRestrictions *model.ViewUsersRestrictions) ([]*model.User, *model.AppError)
|
||||
GetRecentlyActiveUsersForTeam(rctx request.CTX, teamID string) (map[string]*model.User, *model.AppError)
|
||||
GetRecentlyActiveUsersForTeamPage(rctx request.CTX, teamID string, page, perPage int, asAdmin bool, viewRestrictions *model.ViewUsersRestrictions) ([]*model.User, *model.AppError)
|
||||
GetRemoteCluster(remoteClusterId string) (*model.RemoteCluster, *model.AppError)
|
||||
GetRemoteClusterForUser(remoteID string, userID string) (*model.RemoteCluster, *model.AppError)
|
||||
GetRemoteClusterService() (remotecluster.RemoteClusterServiceIFace, *model.AppError)
|
||||
@ -1092,7 +1092,7 @@ type AppIface interface {
|
||||
SessionHasPermissionToReadJob(session model.Session, jobType string) (bool, *model.Permission)
|
||||
SessionHasPermissionToTeam(session model.Session, teamID string, permission *model.Permission) bool
|
||||
SessionHasPermissionToUser(session model.Session, userID string) bool
|
||||
SessionHasPermissionToUserOrBot(session model.Session, userID string) bool
|
||||
SessionHasPermissionToUserOrBot(rctx request.CTX, session model.Session, userID string) bool
|
||||
SetActiveChannel(c request.CTX, userID string, channelID string) *model.AppError
|
||||
SetAutoResponderStatus(rctx request.CTX, user *model.User, oldNotifyProps model.StringMap)
|
||||
SetChannels(ch *Channels)
|
||||
|
@ -217,12 +217,12 @@ func (a *App) SessionHasPermissionToUser(session model.Session, userID string) b
|
||||
return false
|
||||
}
|
||||
|
||||
func (a *App) SessionHasPermissionToUserOrBot(session model.Session, userID string) bool {
|
||||
func (a *App) SessionHasPermissionToUserOrBot(rctx request.CTX, session model.Session, userID string) bool {
|
||||
if session.IsUnrestricted() {
|
||||
return true
|
||||
}
|
||||
|
||||
err := a.SessionHasPermissionToManageBot(session, userID)
|
||||
err := a.SessionHasPermissionToManageBot(rctx, session, userID)
|
||||
if err == nil {
|
||||
return true
|
||||
}
|
||||
@ -339,8 +339,8 @@ func (a *App) RolesGrantPermission(roleNames []string, permissionId string) bool
|
||||
// SessionHasPermissionToManageBot returns nil if the session has access to manage the given bot.
|
||||
// This function deviates from other authorization checks in returning an error instead of just
|
||||
// a boolean, allowing the permission failure to be exposed with more granularity.
|
||||
func (a *App) SessionHasPermissionToManageBot(session model.Session, botUserId string) *model.AppError {
|
||||
existingBot, err := a.GetBot(botUserId, true)
|
||||
func (a *App) SessionHasPermissionToManageBot(rctx request.CTX, session model.Session, botUserId string) *model.AppError {
|
||||
existingBot, err := a.GetBot(rctx, botUserId, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -256,7 +256,7 @@ func TestSessionHasPermissionToManageBot(t *testing.T) {
|
||||
OwnerId: th.BasicUser.Id,
|
||||
})
|
||||
require.Nil(t, err)
|
||||
defer th.App.PermanentDeleteBot(bot.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, bot.UserId)
|
||||
assert.NotNil(t, bot)
|
||||
|
||||
t.Run("test my bot", func(t *testing.T) {
|
||||
@ -264,19 +264,19 @@ func TestSessionHasPermissionToManageBot(t *testing.T) {
|
||||
UserId: th.BasicUser.Id,
|
||||
Roles: model.SystemUserRoleId,
|
||||
}
|
||||
err = th.App.SessionHasPermissionToManageBot(session, bot.UserId)
|
||||
err = th.App.SessionHasPermissionToManageBot(th.Context, session, bot.UserId)
|
||||
assert.NotNil(t, err)
|
||||
assert.Equal(t, "store.sql_bot.get.missing.app_error", err.Id)
|
||||
assert.NoError(t, err.Unwrap())
|
||||
|
||||
th.AddPermissionToRole(model.PermissionReadBots.Id, model.SystemUserRoleId)
|
||||
err = th.App.SessionHasPermissionToManageBot(session, bot.UserId)
|
||||
err = th.App.SessionHasPermissionToManageBot(th.Context, session, bot.UserId)
|
||||
assert.NotNil(t, err)
|
||||
assert.Equal(t, "api.context.permissions.app_error", err.Id)
|
||||
assert.NoError(t, err.Unwrap())
|
||||
|
||||
th.AddPermissionToRole(model.PermissionManageBots.Id, model.SystemUserRoleId)
|
||||
err = th.App.SessionHasPermissionToManageBot(session, bot.UserId)
|
||||
err = th.App.SessionHasPermissionToManageBot(th.Context, session, bot.UserId)
|
||||
assert.Nil(t, err)
|
||||
|
||||
th.RemovePermissionFromRole(model.PermissionReadBots.Id, model.SystemUserRoleId)
|
||||
@ -288,19 +288,19 @@ func TestSessionHasPermissionToManageBot(t *testing.T) {
|
||||
UserId: th.BasicUser2.Id,
|
||||
Roles: model.SystemUserRoleId,
|
||||
}
|
||||
err = th.App.SessionHasPermissionToManageBot(session, bot.UserId)
|
||||
err = th.App.SessionHasPermissionToManageBot(th.Context, session, bot.UserId)
|
||||
assert.NotNil(t, err)
|
||||
assert.Equal(t, "store.sql_bot.get.missing.app_error", err.Id)
|
||||
assert.NoError(t, err.Unwrap())
|
||||
|
||||
th.AddPermissionToRole(model.PermissionReadOthersBots.Id, model.SystemUserRoleId)
|
||||
err = th.App.SessionHasPermissionToManageBot(session, bot.UserId)
|
||||
err = th.App.SessionHasPermissionToManageBot(th.Context, session, bot.UserId)
|
||||
assert.NotNil(t, err)
|
||||
assert.Equal(t, "api.context.permissions.app_error", err.Id)
|
||||
assert.NoError(t, err.Unwrap())
|
||||
|
||||
th.AddPermissionToRole(model.PermissionManageOthersBots.Id, model.SystemUserRoleId)
|
||||
err = th.App.SessionHasPermissionToManageBot(session, bot.UserId)
|
||||
err = th.App.SessionHasPermissionToManageBot(th.Context, session, bot.UserId)
|
||||
assert.Nil(t, err)
|
||||
|
||||
th.RemovePermissionFromRole(model.PermissionReadOthersBots.Id, model.SystemUserRoleId)
|
||||
@ -314,20 +314,20 @@ func TestSessionHasPermissionToManageBot(t *testing.T) {
|
||||
}
|
||||
|
||||
// test non bot, contains wrapped error
|
||||
err = th.App.SessionHasPermissionToManageBot(session, "12345")
|
||||
err = th.App.SessionHasPermissionToManageBot(th.Context, session, "12345")
|
||||
assert.NotNil(t, err)
|
||||
assert.Equal(t, "store.sql_bot.get.missing.app_error", err.Id)
|
||||
assert.Error(t, err.Unwrap())
|
||||
|
||||
// test existing bot, without PermissionManageOthersBots - no wrapped error
|
||||
err = th.App.SessionHasPermissionToManageBot(session, bot.UserId)
|
||||
err = th.App.SessionHasPermissionToManageBot(th.Context, session, bot.UserId)
|
||||
assert.NotNil(t, err)
|
||||
assert.Equal(t, "store.sql_bot.get.missing.app_error", err.Id)
|
||||
assert.NoError(t, err.Unwrap())
|
||||
|
||||
// test with correct permissions
|
||||
th.AddPermissionToRole(model.PermissionManageOthersBots.Id, model.SystemUserManagerRoleId)
|
||||
err = th.App.SessionHasPermissionToManageBot(session, bot.UserId)
|
||||
err = th.App.SessionHasPermissionToManageBot(th.Context, session, bot.UserId)
|
||||
assert.Nil(t, err)
|
||||
|
||||
th.RemovePermissionFromRole(model.PermissionManageOthersBots.Id, model.SystemUserManagerRoleId)
|
||||
@ -338,7 +338,7 @@ func TestSessionHasPermissionToManageBot(t *testing.T) {
|
||||
UserId: th.SystemAdminUser.Id,
|
||||
Roles: model.SystemAdminRoleId,
|
||||
}
|
||||
err = th.App.SessionHasPermissionToManageBot(session, bot.UserId)
|
||||
err = th.App.SessionHasPermissionToManageBot(th.Context, session, bot.UserId)
|
||||
assert.Nil(t, err)
|
||||
})
|
||||
|
||||
@ -347,7 +347,7 @@ func TestSessionHasPermissionToManageBot(t *testing.T) {
|
||||
UserId: th.SystemAdminUser.Id,
|
||||
Roles: model.SystemUserRoleId,
|
||||
}
|
||||
err = th.App.SessionHasPermissionToManageBot(session, "12345")
|
||||
err = th.App.SessionHasPermissionToManageBot(th.Context, session, "12345")
|
||||
assert.NotNil(t, err)
|
||||
assert.Equal(t, "store.sql_bot.get.missing.app_error", err.Id)
|
||||
assert.Error(t, err.Unwrap())
|
||||
@ -385,7 +385,7 @@ func TestSessionHasPermissionToUser(t *testing.T) {
|
||||
})
|
||||
require.Nil(t, err)
|
||||
assert.NotNil(t, bot)
|
||||
defer th.App.PermanentDeleteBot(bot.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, bot.UserId)
|
||||
|
||||
assert.False(t, th.App.SessionHasPermissionToUser(session, bot.UserId))
|
||||
})
|
||||
@ -410,16 +410,16 @@ func TestSessionHasPermissionToManageUserOrBot(t *testing.T) {
|
||||
OwnerId: th.BasicUser.Id,
|
||||
})
|
||||
require.Nil(t, err)
|
||||
defer th.App.PermanentDeleteBot(bot.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, bot.UserId)
|
||||
|
||||
t.Run("test basic user access", func(t *testing.T) {
|
||||
session := model.Session{
|
||||
UserId: th.BasicUser.Id,
|
||||
Roles: model.SystemUserRoleId,
|
||||
}
|
||||
assert.True(t, th.App.SessionHasPermissionToUserOrBot(session, th.BasicUser.Id))
|
||||
assert.False(t, th.App.SessionHasPermissionToUserOrBot(session, bot.UserId))
|
||||
assert.False(t, th.App.SessionHasPermissionToUserOrBot(session, th.BasicUser2.Id))
|
||||
assert.True(t, th.App.SessionHasPermissionToUserOrBot(th.Context, session, th.BasicUser.Id))
|
||||
assert.False(t, th.App.SessionHasPermissionToUserOrBot(th.Context, session, bot.UserId))
|
||||
assert.False(t, th.App.SessionHasPermissionToUserOrBot(th.Context, session, th.BasicUser2.Id))
|
||||
})
|
||||
|
||||
t.Run("test user manager access", func(t *testing.T) {
|
||||
@ -427,18 +427,18 @@ func TestSessionHasPermissionToManageUserOrBot(t *testing.T) {
|
||||
UserId: th.BasicUser2.Id,
|
||||
Roles: model.SystemUserManagerRoleId,
|
||||
}
|
||||
assert.False(t, th.App.SessionHasPermissionToUserOrBot(session, th.BasicUser.Id))
|
||||
assert.True(t, th.App.SessionHasPermissionToUserOrBot(session, th.BasicUser2.Id))
|
||||
assert.False(t, th.App.SessionHasPermissionToUserOrBot(session, bot.UserId))
|
||||
assert.False(t, th.App.SessionHasPermissionToUserOrBot(th.Context, session, th.BasicUser.Id))
|
||||
assert.True(t, th.App.SessionHasPermissionToUserOrBot(th.Context, session, th.BasicUser2.Id))
|
||||
assert.False(t, th.App.SessionHasPermissionToUserOrBot(th.Context, session, bot.UserId))
|
||||
|
||||
th.AddPermissionToRole(model.PermissionEditOtherUsers.Id, model.SystemUserManagerRoleId)
|
||||
assert.True(t, th.App.SessionHasPermissionToUserOrBot(session, th.BasicUser.Id))
|
||||
assert.False(t, th.App.SessionHasPermissionToUserOrBot(session, bot.UserId))
|
||||
assert.True(t, th.App.SessionHasPermissionToUserOrBot(th.Context, session, th.BasicUser.Id))
|
||||
assert.False(t, th.App.SessionHasPermissionToUserOrBot(th.Context, session, bot.UserId))
|
||||
th.RemovePermissionFromRole(model.PermissionEditOtherUsers.Id, model.SystemUserManagerRoleId)
|
||||
|
||||
th.AddPermissionToRole(model.PermissionManageOthersBots.Id, model.SystemUserManagerRoleId)
|
||||
assert.False(t, th.App.SessionHasPermissionToUserOrBot(session, th.BasicUser.Id))
|
||||
assert.True(t, th.App.SessionHasPermissionToUserOrBot(session, bot.UserId))
|
||||
assert.False(t, th.App.SessionHasPermissionToUserOrBot(th.Context, session, th.BasicUser.Id))
|
||||
assert.True(t, th.App.SessionHasPermissionToUserOrBot(th.Context, session, bot.UserId))
|
||||
th.RemovePermissionFromRole(model.PermissionManageOthersBots.Id, model.SystemUserManagerRoleId)
|
||||
})
|
||||
|
||||
@ -447,8 +447,8 @@ func TestSessionHasPermissionToManageUserOrBot(t *testing.T) {
|
||||
UserId: th.SystemAdminUser.Id,
|
||||
Roles: model.SystemAdminRoleId,
|
||||
}
|
||||
assert.True(t, th.App.SessionHasPermissionToUserOrBot(session, bot.UserId))
|
||||
assert.True(t, th.App.SessionHasPermissionToUserOrBot(session, th.BasicUser.Id))
|
||||
assert.True(t, th.App.SessionHasPermissionToUserOrBot(th.Context, session, bot.UserId))
|
||||
assert.True(t, th.App.SessionHasPermissionToUserOrBot(th.Context, session, th.BasicUser.Id))
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -89,13 +89,13 @@ func (a *App) EnsureBot(rctx request.CTX, pluginID string, bot *model.Bot) (stri
|
||||
}
|
||||
|
||||
// CreateBot creates the given bot and corresponding user.
|
||||
func (a *App) CreateBot(c request.CTX, bot *model.Bot) (*model.Bot, *model.AppError) {
|
||||
func (a *App) CreateBot(rctx request.CTX, bot *model.Bot) (*model.Bot, *model.AppError) {
|
||||
vErr := bot.IsValidCreate()
|
||||
if vErr != nil {
|
||||
return nil, vErr
|
||||
}
|
||||
|
||||
user, nErr := a.Srv().Store().User().Save(c, model.UserFromBot(bot))
|
||||
user, nErr := a.Srv().Store().User().Save(rctx, model.UserFromBot(bot))
|
||||
if nErr != nil {
|
||||
var appErr *model.AppError
|
||||
var invErr *store.ErrInvalidInput
|
||||
@ -139,7 +139,7 @@ func (a *App) CreateBot(c request.CTX, bot *model.Bot) (*model.Bot, *model.AppEr
|
||||
} else if ownerUser != nil {
|
||||
// Send a message to the bot's creator to inform them that the bot needs to be added
|
||||
// to a team and channel after it's created
|
||||
channel, err := a.getOrCreateDirectChannelWithUser(c, user, ownerUser)
|
||||
channel, err := a.getOrCreateDirectChannelWithUser(rctx, user, ownerUser)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -152,7 +152,7 @@ func (a *App) CreateBot(c request.CTX, bot *model.Bot) (*model.Bot, *model.AppEr
|
||||
Message: T("api.bot.teams_channels.add_message_mobile"),
|
||||
}
|
||||
|
||||
if _, err := a.CreatePostAsUser(c, botAddPost, c.Session().Id, true); err != nil {
|
||||
if _, err := a.CreatePostAsUser(rctx, botAddPost, rctx.Session().Id, true); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
@ -241,7 +241,7 @@ func (a *App) getOrCreateBot(rctx request.CTX, botDef *model.Bot) (*model.Bot, *
|
||||
}
|
||||
|
||||
//return the bot for this user
|
||||
savedBot, appErr := a.GetBot(botUser.Id, false)
|
||||
savedBot, appErr := a.GetBot(rctx, botUser.Id, false)
|
||||
if appErr != nil {
|
||||
return nil, appErr
|
||||
}
|
||||
@ -251,7 +251,7 @@ func (a *App) getOrCreateBot(rctx request.CTX, botDef *model.Bot) (*model.Bot, *
|
||||
|
||||
// PatchBot applies the given patch to the bot and corresponding user.
|
||||
func (a *App) PatchBot(rctx request.CTX, botUserId string, botPatch *model.BotPatch) (*model.Bot, *model.AppError) {
|
||||
bot, err := a.GetBot(botUserId, true)
|
||||
bot, err := a.GetBot(rctx, botUserId, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -320,7 +320,7 @@ func (a *App) PatchBot(rctx request.CTX, botUserId string, botPatch *model.BotPa
|
||||
}
|
||||
|
||||
// GetBot returns the given bot.
|
||||
func (a *App) GetBot(botUserId string, includeDeleted bool) (*model.Bot, *model.AppError) {
|
||||
func (a *App) GetBot(rctx request.CTX, botUserId string, includeDeleted bool) (*model.Bot, *model.AppError) {
|
||||
bot, err := a.Srv().Store().Bot().Get(botUserId, includeDeleted)
|
||||
if err != nil {
|
||||
var nfErr *store.ErrNotFound
|
||||
@ -335,7 +335,7 @@ func (a *App) GetBot(botUserId string, includeDeleted bool) (*model.Bot, *model.
|
||||
}
|
||||
|
||||
// GetBots returns the requested page of bots.
|
||||
func (a *App) GetBots(options *model.BotGetOptions) (model.BotList, *model.AppError) {
|
||||
func (a *App) GetBots(rctx request.CTX, options *model.BotGetOptions) (model.BotList, *model.AppError) {
|
||||
bots, err := a.Srv().Store().Bot().GetAll(options)
|
||||
if err != nil {
|
||||
return nil, model.NewAppError("GetBots", "app.bot.getbots.internal_error", nil, "", http.StatusInternalServerError).Wrap(err)
|
||||
@ -344,7 +344,7 @@ func (a *App) GetBots(options *model.BotGetOptions) (model.BotList, *model.AppEr
|
||||
}
|
||||
|
||||
// UpdateBotActive marks a bot as active or inactive, along with its corresponding user.
|
||||
func (a *App) UpdateBotActive(c request.CTX, botUserId string, active bool) (*model.Bot, *model.AppError) {
|
||||
func (a *App) UpdateBotActive(rctx request.CTX, botUserId string, active bool) (*model.Bot, *model.AppError) {
|
||||
user, nErr := a.Srv().Store().User().Get(context.Background(), botUserId)
|
||||
if nErr != nil {
|
||||
var nfErr *store.ErrNotFound
|
||||
@ -356,7 +356,7 @@ func (a *App) UpdateBotActive(c request.CTX, botUserId string, active bool) (*mo
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := a.UpdateActive(c, user, active); err != nil {
|
||||
if _, err := a.UpdateActive(rctx, user, active); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -400,7 +400,7 @@ func (a *App) UpdateBotActive(c request.CTX, botUserId string, active bool) (*mo
|
||||
}
|
||||
|
||||
// PermanentDeleteBot permanently deletes a bot and its corresponding user.
|
||||
func (a *App) PermanentDeleteBot(botUserId string) *model.AppError {
|
||||
func (a *App) PermanentDeleteBot(rctx request.CTX, botUserId string) *model.AppError {
|
||||
if err := a.Srv().Store().Bot().PermanentDelete(botUserId); err != nil {
|
||||
var invErr *store.ErrInvalidInput
|
||||
switch {
|
||||
@ -419,7 +419,7 @@ func (a *App) PermanentDeleteBot(botUserId string) *model.AppError {
|
||||
}
|
||||
|
||||
// UpdateBotOwner changes a bot's owner to the given value.
|
||||
func (a *App) UpdateBotOwner(botUserId, newOwnerId string) (*model.Bot, *model.AppError) {
|
||||
func (a *App) UpdateBotOwner(rctx request.CTX, botUserId, newOwnerId string) (*model.Bot, *model.AppError) {
|
||||
bot, err := a.Srv().Store().Bot().Get(botUserId, true)
|
||||
if err != nil {
|
||||
var nfErr *store.ErrNotFound
|
||||
@ -451,7 +451,7 @@ func (a *App) UpdateBotOwner(botUserId, newOwnerId string) (*model.Bot, *model.A
|
||||
}
|
||||
|
||||
// disableUserBots disables all bots owned by the given user.
|
||||
func (a *App) disableUserBots(c request.CTX, userID string) *model.AppError {
|
||||
func (a *App) disableUserBots(rctx request.CTX, userID string) *model.AppError {
|
||||
perPage := 20
|
||||
for {
|
||||
options := &model.BotGetOptions{
|
||||
@ -461,15 +461,15 @@ func (a *App) disableUserBots(c request.CTX, userID string) *model.AppError {
|
||||
Page: 0,
|
||||
PerPage: perPage,
|
||||
}
|
||||
userBots, err := a.GetBots(options)
|
||||
userBots, err := a.GetBots(rctx, options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, bot := range userBots {
|
||||
_, err := a.UpdateBotActive(c, bot.UserId, false)
|
||||
_, err := a.UpdateBotActive(rctx, bot.UserId, false)
|
||||
if err != nil {
|
||||
c.Logger().Warn("Unable to deactivate bot.", mlog.String("bot_user_id", bot.UserId), mlog.Err(err))
|
||||
rctx.Logger().Warn("Unable to deactivate bot.", mlog.String("bot_user_id", bot.UserId), mlog.Err(err))
|
||||
}
|
||||
}
|
||||
|
||||
@ -484,7 +484,7 @@ func (a *App) disableUserBots(c request.CTX, userID string) *model.AppError {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *App) notifySysadminsBotOwnerDeactivated(c request.CTX, userID string) *model.AppError {
|
||||
func (a *App) notifySysadminsBotOwnerDeactivated(rctx request.CTX, userID string) *model.AppError {
|
||||
perPage := 25
|
||||
botOptions := &model.BotGetOptions{
|
||||
OwnerId: userID,
|
||||
@ -496,7 +496,7 @@ func (a *App) notifySysadminsBotOwnerDeactivated(c request.CTX, userID string) *
|
||||
// get owner bots
|
||||
var userBots []*model.Bot
|
||||
for {
|
||||
bots, err := a.GetBots(botOptions)
|
||||
bots, err := a.GetBots(rctx, botOptions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -546,7 +546,7 @@ func (a *App) notifySysadminsBotOwnerDeactivated(c request.CTX, userID string) *
|
||||
|
||||
// for each sysadmin, notify user that owns bots was disabled
|
||||
for _, sysAdmin := range sysAdmins {
|
||||
channel, appErr := a.GetOrCreateDirectChannel(c, sysAdmin.Id, sysAdmin.Id)
|
||||
channel, appErr := a.GetOrCreateDirectChannel(rctx, sysAdmin.Id, sysAdmin.Id)
|
||||
if appErr != nil {
|
||||
return appErr
|
||||
}
|
||||
@ -558,7 +558,7 @@ func (a *App) notifySysadminsBotOwnerDeactivated(c request.CTX, userID string) *
|
||||
Type: model.PostTypeSystemGeneric,
|
||||
}
|
||||
|
||||
_, appErr = a.CreatePost(c, post, channel, false, true)
|
||||
_, appErr = a.CreatePost(rctx, post, channel, false, true)
|
||||
if appErr != nil {
|
||||
return appErr
|
||||
}
|
||||
@ -596,7 +596,7 @@ func (a *App) getDisableBotSysadminMessage(user *model.User, userBots model.BotL
|
||||
}
|
||||
|
||||
// ConvertUserToBot converts a user to bot.
|
||||
func (a *App) ConvertUserToBot(user *model.User) (*model.Bot, *model.AppError) {
|
||||
func (a *App) ConvertUserToBot(rctx request.CTX, user *model.User) (*model.Bot, *model.AppError) {
|
||||
bot, err := a.Srv().Store().Bot().Save(model.BotFromUser(user))
|
||||
if err != nil {
|
||||
var appErr *model.AppError
|
||||
|
@ -79,7 +79,7 @@ func TestCreateBot(t *testing.T) {
|
||||
OwnerId: th.BasicUser.Id,
|
||||
})
|
||||
require.Nil(t, err)
|
||||
defer th.App.PermanentDeleteBot(bot.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, bot.UserId)
|
||||
assert.Equal(t, "username", bot.Username)
|
||||
assert.Equal(t, "a bot", bot.Description)
|
||||
assert.Equal(t, th.BasicUser.Id, bot.OwnerId)
|
||||
@ -123,7 +123,7 @@ func TestPatchBot(t *testing.T) {
|
||||
OwnerId: th.BasicUser.Id,
|
||||
})
|
||||
require.Nil(t, err)
|
||||
defer th.App.PermanentDeleteBot(bot.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, bot.UserId)
|
||||
|
||||
botPatch := &model.BotPatch{
|
||||
Username: sToP("invalid username"),
|
||||
@ -146,7 +146,7 @@ func TestPatchBot(t *testing.T) {
|
||||
OwnerId: th.BasicUser.Id,
|
||||
})
|
||||
require.Nil(t, err)
|
||||
defer th.App.PermanentDeleteBot(bot.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, bot.UserId)
|
||||
|
||||
botPatch := &model.BotPatch{
|
||||
Username: sToP("username"),
|
||||
@ -172,7 +172,7 @@ func TestPatchBot(t *testing.T) {
|
||||
|
||||
createdBot, err := th.App.CreateBot(th.Context, bot)
|
||||
require.Nil(t, err)
|
||||
defer th.App.PermanentDeleteBot(createdBot.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, createdBot.UserId)
|
||||
|
||||
botPatch := &model.BotPatch{
|
||||
Username: sToP("username2"),
|
||||
@ -204,7 +204,7 @@ func TestPatchBot(t *testing.T) {
|
||||
OwnerId: th.BasicUser.Id,
|
||||
})
|
||||
require.Nil(t, err)
|
||||
defer th.App.PermanentDeleteBot(bot.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, bot.UserId)
|
||||
|
||||
botPatch := &model.BotPatch{
|
||||
Username: sToP(th.BasicUser2.Username),
|
||||
@ -226,7 +226,7 @@ func TestGetBot(t *testing.T) {
|
||||
OwnerId: th.BasicUser.Id,
|
||||
})
|
||||
require.Nil(t, err)
|
||||
defer th.App.PermanentDeleteBot(bot1.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, bot1.UserId)
|
||||
|
||||
bot2, err := th.App.CreateBot(th.Context, &model.Bot{
|
||||
Username: "username2",
|
||||
@ -234,7 +234,7 @@ func TestGetBot(t *testing.T) {
|
||||
OwnerId: th.BasicUser.Id,
|
||||
})
|
||||
require.Nil(t, err)
|
||||
defer th.App.PermanentDeleteBot(bot2.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, bot2.UserId)
|
||||
|
||||
deletedBot, err := th.App.CreateBot(th.Context, &model.Bot{
|
||||
Username: "username3",
|
||||
@ -244,34 +244,34 @@ func TestGetBot(t *testing.T) {
|
||||
require.Nil(t, err)
|
||||
deletedBot, err = th.App.UpdateBotActive(th.Context, deletedBot.UserId, false)
|
||||
require.Nil(t, err)
|
||||
defer th.App.PermanentDeleteBot(deletedBot.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, deletedBot.UserId)
|
||||
|
||||
t.Run("get unknown bot", func(t *testing.T) {
|
||||
_, err := th.App.GetBot(model.NewId(), false)
|
||||
_, err := th.App.GetBot(th.Context, model.NewId(), false)
|
||||
require.NotNil(t, err)
|
||||
require.Equal(t, "store.sql_bot.get.missing.app_error", err.Id)
|
||||
})
|
||||
|
||||
t.Run("get bot1", func(t *testing.T) {
|
||||
bot, err := th.App.GetBot(bot1.UserId, false)
|
||||
bot, err := th.App.GetBot(th.Context, bot1.UserId, false)
|
||||
require.Nil(t, err)
|
||||
assert.Equal(t, bot1, bot)
|
||||
})
|
||||
|
||||
t.Run("get bot2", func(t *testing.T) {
|
||||
bot, err := th.App.GetBot(bot2.UserId, false)
|
||||
bot, err := th.App.GetBot(th.Context, bot2.UserId, false)
|
||||
require.Nil(t, err)
|
||||
assert.Equal(t, bot2, bot)
|
||||
})
|
||||
|
||||
t.Run("get deleted bot", func(t *testing.T) {
|
||||
_, err := th.App.GetBot(deletedBot.UserId, false)
|
||||
_, err := th.App.GetBot(th.Context, deletedBot.UserId, false)
|
||||
require.NotNil(t, err)
|
||||
require.Equal(t, "store.sql_bot.get.missing.app_error", err.Id)
|
||||
})
|
||||
|
||||
t.Run("get deleted bot, include deleted", func(t *testing.T) {
|
||||
bot, err := th.App.GetBot(deletedBot.UserId, true)
|
||||
bot, err := th.App.GetBot(th.Context, deletedBot.UserId, true)
|
||||
require.Nil(t, err)
|
||||
assert.Equal(t, deletedBot, bot)
|
||||
})
|
||||
@ -290,7 +290,7 @@ func TestGetBots(t *testing.T) {
|
||||
OwnerId: OwnerId1,
|
||||
})
|
||||
require.Nil(t, err)
|
||||
defer th.App.PermanentDeleteBot(bot1.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, bot1.UserId)
|
||||
|
||||
deletedBot1, err := th.App.CreateBot(th.Context, &model.Bot{
|
||||
Username: "username4",
|
||||
@ -300,7 +300,7 @@ func TestGetBots(t *testing.T) {
|
||||
require.Nil(t, err)
|
||||
deletedBot1, err = th.App.UpdateBotActive(th.Context, deletedBot1.UserId, false)
|
||||
require.Nil(t, err)
|
||||
defer th.App.PermanentDeleteBot(deletedBot1.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, deletedBot1.UserId)
|
||||
|
||||
bot2, err := th.App.CreateBot(th.Context, &model.Bot{
|
||||
Username: "username2",
|
||||
@ -308,7 +308,7 @@ func TestGetBots(t *testing.T) {
|
||||
OwnerId: OwnerId1,
|
||||
})
|
||||
require.Nil(t, err)
|
||||
defer th.App.PermanentDeleteBot(bot2.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, bot2.UserId)
|
||||
|
||||
bot3, err := th.App.CreateBot(th.Context, &model.Bot{
|
||||
Username: "username3",
|
||||
@ -316,7 +316,7 @@ func TestGetBots(t *testing.T) {
|
||||
OwnerId: OwnerId1,
|
||||
})
|
||||
require.Nil(t, err)
|
||||
defer th.App.PermanentDeleteBot(bot3.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, bot3.UserId)
|
||||
|
||||
bot4, err := th.App.CreateBot(th.Context, &model.Bot{
|
||||
Username: "username5",
|
||||
@ -324,7 +324,7 @@ func TestGetBots(t *testing.T) {
|
||||
OwnerId: OwnerId2,
|
||||
})
|
||||
require.Nil(t, err)
|
||||
defer th.App.PermanentDeleteBot(bot4.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, bot4.UserId)
|
||||
|
||||
deletedBot2, err := th.App.CreateBot(th.Context, &model.Bot{
|
||||
Username: "username6",
|
||||
@ -334,10 +334,10 @@ func TestGetBots(t *testing.T) {
|
||||
require.Nil(t, err)
|
||||
deletedBot2, err = th.App.UpdateBotActive(th.Context, deletedBot2.UserId, false)
|
||||
require.Nil(t, err)
|
||||
defer th.App.PermanentDeleteBot(deletedBot2.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, deletedBot2.UserId)
|
||||
|
||||
t.Run("get bots, page=0, perPage=10", func(t *testing.T) {
|
||||
bots, err := th.App.GetBots(&model.BotGetOptions{
|
||||
bots, err := th.App.GetBots(th.Context, &model.BotGetOptions{
|
||||
Page: 0,
|
||||
PerPage: 10,
|
||||
OwnerId: "",
|
||||
@ -348,7 +348,7 @@ func TestGetBots(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("get bots, page=0, perPage=1", func(t *testing.T) {
|
||||
bots, err := th.App.GetBots(&model.BotGetOptions{
|
||||
bots, err := th.App.GetBots(th.Context, &model.BotGetOptions{
|
||||
Page: 0,
|
||||
PerPage: 1,
|
||||
OwnerId: "",
|
||||
@ -359,7 +359,7 @@ func TestGetBots(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("get bots, page=1, perPage=2", func(t *testing.T) {
|
||||
bots, err := th.App.GetBots(&model.BotGetOptions{
|
||||
bots, err := th.App.GetBots(th.Context, &model.BotGetOptions{
|
||||
Page: 1,
|
||||
PerPage: 2,
|
||||
OwnerId: "",
|
||||
@ -370,7 +370,7 @@ func TestGetBots(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("get bots, page=2, perPage=2", func(t *testing.T) {
|
||||
bots, err := th.App.GetBots(&model.BotGetOptions{
|
||||
bots, err := th.App.GetBots(th.Context, &model.BotGetOptions{
|
||||
Page: 2,
|
||||
PerPage: 2,
|
||||
OwnerId: "",
|
||||
@ -381,7 +381,7 @@ func TestGetBots(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("get bots, page=0, perPage=10, include deleted", func(t *testing.T) {
|
||||
bots, err := th.App.GetBots(&model.BotGetOptions{
|
||||
bots, err := th.App.GetBots(th.Context, &model.BotGetOptions{
|
||||
Page: 0,
|
||||
PerPage: 10,
|
||||
OwnerId: "",
|
||||
@ -392,7 +392,7 @@ func TestGetBots(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("get bots, page=0, perPage=1, include deleted", func(t *testing.T) {
|
||||
bots, err := th.App.GetBots(&model.BotGetOptions{
|
||||
bots, err := th.App.GetBots(th.Context, &model.BotGetOptions{
|
||||
Page: 0,
|
||||
PerPage: 1,
|
||||
OwnerId: "",
|
||||
@ -403,7 +403,7 @@ func TestGetBots(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("get bots, page=1, perPage=2, include deleted", func(t *testing.T) {
|
||||
bots, err := th.App.GetBots(&model.BotGetOptions{
|
||||
bots, err := th.App.GetBots(th.Context, &model.BotGetOptions{
|
||||
Page: 1,
|
||||
PerPage: 2,
|
||||
OwnerId: "",
|
||||
@ -414,7 +414,7 @@ func TestGetBots(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("get bots, page=2, perPage=2, include deleted", func(t *testing.T) {
|
||||
bots, err := th.App.GetBots(&model.BotGetOptions{
|
||||
bots, err := th.App.GetBots(th.Context, &model.BotGetOptions{
|
||||
Page: 2,
|
||||
PerPage: 2,
|
||||
OwnerId: "",
|
||||
@ -425,7 +425,7 @@ func TestGetBots(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("get offset=0, limit=10, creator id 1", func(t *testing.T) {
|
||||
bots, err := th.App.GetBots(&model.BotGetOptions{
|
||||
bots, err := th.App.GetBots(th.Context, &model.BotGetOptions{
|
||||
Page: 0,
|
||||
PerPage: 10,
|
||||
OwnerId: OwnerId1,
|
||||
@ -436,7 +436,7 @@ func TestGetBots(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("get offset=0, limit=10, creator id 2", func(t *testing.T) {
|
||||
bots, err := th.App.GetBots(&model.BotGetOptions{
|
||||
bots, err := th.App.GetBots(th.Context, &model.BotGetOptions{
|
||||
Page: 0,
|
||||
PerPage: 10,
|
||||
OwnerId: OwnerId2,
|
||||
@ -447,7 +447,7 @@ func TestGetBots(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("get offset=0, limit=10, include deleted, creator id 1", func(t *testing.T) {
|
||||
bots, err := th.App.GetBots(&model.BotGetOptions{
|
||||
bots, err := th.App.GetBots(th.Context, &model.BotGetOptions{
|
||||
Page: 0,
|
||||
PerPage: 10,
|
||||
OwnerId: OwnerId1,
|
||||
@ -458,7 +458,7 @@ func TestGetBots(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("get offset=0, limit=10, include deleted, creator id 2", func(t *testing.T) {
|
||||
bots, err := th.App.GetBots(&model.BotGetOptions{
|
||||
bots, err := th.App.GetBots(th.Context, &model.BotGetOptions{
|
||||
Page: 0,
|
||||
PerPage: 10,
|
||||
OwnerId: OwnerId2,
|
||||
@ -489,7 +489,7 @@ func TestUpdateBotActive(t *testing.T) {
|
||||
OwnerId: th.BasicUser.Id,
|
||||
})
|
||||
require.Nil(t, err)
|
||||
defer th.App.PermanentDeleteBot(bot.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, bot.UserId)
|
||||
|
||||
disabledBot, err := th.App.UpdateBotActive(th.Context, bot.UserId, false)
|
||||
require.Nil(t, err)
|
||||
@ -522,9 +522,9 @@ func TestPermanentDeleteBot(t *testing.T) {
|
||||
})
|
||||
require.Nil(t, err)
|
||||
|
||||
require.Nil(t, th.App.PermanentDeleteBot(bot.UserId))
|
||||
require.Nil(t, th.App.PermanentDeleteBot(th.Context, bot.UserId))
|
||||
|
||||
_, err = th.App.GetBot(bot.UserId, false)
|
||||
_, err = th.App.GetBot(th.Context, bot.UserId, false)
|
||||
require.NotNil(t, err)
|
||||
require.Equal(t, "store.sql_bot.get.missing.app_error", err.Id)
|
||||
}
|
||||
@ -539,7 +539,7 @@ func TestDisableUserBots(t *testing.T) {
|
||||
bots := []*model.Bot{}
|
||||
defer func() {
|
||||
for _, bot := range bots {
|
||||
th.App.PermanentDeleteBot(bot.UserId)
|
||||
th.App.PermanentDeleteBot(th.Context, bot.UserId)
|
||||
}
|
||||
}()
|
||||
|
||||
@ -560,20 +560,20 @@ func TestDisableUserBots(t *testing.T) {
|
||||
OwnerId: ownerId2,
|
||||
})
|
||||
require.Nil(t, err)
|
||||
defer th.App.PermanentDeleteBot(u2bot1.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, u2bot1.UserId)
|
||||
|
||||
err = th.App.disableUserBots(th.Context, ownerId1)
|
||||
require.Nil(t, err)
|
||||
|
||||
// Check all bots and corresponding users are disabled for creator 1
|
||||
for _, bot := range bots {
|
||||
retbot, err2 := th.App.GetBot(bot.UserId, true)
|
||||
retbot, err2 := th.App.GetBot(th.Context, bot.UserId, true)
|
||||
require.Nil(t, err2)
|
||||
require.NotZero(t, retbot.DeleteAt, bot.Username)
|
||||
}
|
||||
|
||||
// Check bots and corresponding user not disabled for creator 2
|
||||
bot, err := th.App.GetBot(u2bot1.UserId, true)
|
||||
bot, err := th.App.GetBot(th.Context, u2bot1.UserId, true)
|
||||
require.Nil(t, err)
|
||||
require.Zero(t, bot.DeleteAt)
|
||||
|
||||
@ -593,7 +593,7 @@ func TestNotifySysadminsBotOwnerDisabled(t *testing.T) {
|
||||
userBots := []*model.Bot{}
|
||||
defer func() {
|
||||
for _, bot := range userBots {
|
||||
th.App.PermanentDeleteBot(bot.UserId)
|
||||
th.App.PermanentDeleteBot(th.Context, bot.UserId)
|
||||
}
|
||||
}()
|
||||
|
||||
@ -725,7 +725,7 @@ func TestConvertUserToBot(t *testing.T) {
|
||||
th := Setup(t).InitBasic()
|
||||
defer th.TearDown()
|
||||
|
||||
_, err := th.App.ConvertUserToBot(&model.User{
|
||||
_, err := th.App.ConvertUserToBot(th.Context, &model.User{
|
||||
Username: "username",
|
||||
Id: "",
|
||||
})
|
||||
@ -737,7 +737,7 @@ func TestConvertUserToBot(t *testing.T) {
|
||||
th := Setup(t).InitBasic()
|
||||
defer th.TearDown()
|
||||
|
||||
_, err := th.App.ConvertUserToBot(&model.User{
|
||||
_, err := th.App.ConvertUserToBot(th.Context, &model.User{
|
||||
Username: "invalid username",
|
||||
Id: th.BasicUser.Id,
|
||||
})
|
||||
@ -750,12 +750,12 @@ func TestConvertUserToBot(t *testing.T) {
|
||||
th := Setup(t).InitBasic()
|
||||
defer th.TearDown()
|
||||
|
||||
bot, err := th.App.ConvertUserToBot(&model.User{
|
||||
bot, err := th.App.ConvertUserToBot(th.Context, &model.User{
|
||||
Username: "username",
|
||||
Id: th.BasicUser.Id,
|
||||
})
|
||||
require.Nil(t, err)
|
||||
defer th.App.PermanentDeleteBot(bot.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, bot.UserId)
|
||||
assert.Equal(t, "username", bot.Username)
|
||||
assert.Equal(t, th.BasicUser.Id, bot.OwnerId)
|
||||
})
|
||||
|
@ -1580,7 +1580,7 @@ func TestAddUserToChannel(t *testing.T) {
|
||||
defer th.App.PermanentDeleteUser(th.Context, &user1)
|
||||
bot := th.CreateBot()
|
||||
botUser, _ := th.App.GetUser(bot.UserId)
|
||||
defer th.App.PermanentDeleteBot(botUser.Id)
|
||||
defer th.App.PermanentDeleteBot(th.Context, botUser.Id)
|
||||
|
||||
th.App.AddTeamMember(th.Context, th.BasicTeam.Id, ruser1.Id)
|
||||
th.App.AddTeamMember(th.Context, th.BasicTeam.Id, bot.UserId)
|
||||
@ -1662,7 +1662,7 @@ func TestRemoveUserFromChannel(t *testing.T) {
|
||||
|
||||
bot := th.CreateBot()
|
||||
botUser, _ := th.App.GetUser(bot.UserId)
|
||||
defer th.App.PermanentDeleteBot(botUser.Id)
|
||||
defer th.App.PermanentDeleteBot(th.Context, botUser.Id)
|
||||
|
||||
th.App.AddTeamMember(th.Context, th.BasicTeam.Id, ruser.Id)
|
||||
th.App.AddTeamMember(th.Context, th.BasicTeam.Id, bot.UserId)
|
||||
|
@ -278,9 +278,9 @@ func (th *TestHelper) InitBasic() *TestHelper {
|
||||
}
|
||||
|
||||
func (th *TestHelper) DeleteBots() *TestHelper {
|
||||
preexistingBots, _ := th.App.GetBots(&model.BotGetOptions{Page: 0, PerPage: 100})
|
||||
preexistingBots, _ := th.App.GetBots(th.Context, &model.BotGetOptions{Page: 0, PerPage: 100})
|
||||
for _, bot := range preexistingBots {
|
||||
th.App.PermanentDeleteBot(bot.UserId)
|
||||
th.App.PermanentDeleteBot(th.Context, bot.UserId)
|
||||
}
|
||||
return th
|
||||
}
|
||||
|
@ -114,7 +114,7 @@ func TestGetUserLimits(t *testing.T) {
|
||||
require.Equal(t, int64(3), userLimits.ActiveUserCount)
|
||||
|
||||
// now we'll delete the bot
|
||||
_ = th.App.PermanentDeleteBot(newBot.UserId)
|
||||
_ = th.App.PermanentDeleteBot(th.Context, newBot.UserId)
|
||||
userLimits, appErr = th.App.GetUserLimits()
|
||||
require.Nil(t, appErr)
|
||||
require.Equal(t, int64(3), userLimits.ActiveUserCount)
|
||||
|
@ -2463,7 +2463,7 @@ func TestUserAllowsEmail(t *testing.T) {
|
||||
t.Run("should return false in the case user is a bot", func(t *testing.T) {
|
||||
user := th.CreateUser()
|
||||
|
||||
th.App.ConvertUserToBot(user)
|
||||
th.App.ConvertUserToBot(th.Context, user)
|
||||
|
||||
channelMemberNotifcationProps := model.StringMap{
|
||||
model.EmailNotifyProp: model.ChannelNotifyDefault,
|
||||
|
@ -1884,7 +1884,7 @@ func (a *OpenTracingAppLayer) ConvertGroupMessageToChannel(c request.CTX, conver
|
||||
return resultVar0, resultVar1
|
||||
}
|
||||
|
||||
func (a *OpenTracingAppLayer) ConvertUserToBot(user *model.User) (*model.Bot, *model.AppError) {
|
||||
func (a *OpenTracingAppLayer) ConvertUserToBot(rctx request.CTX, user *model.User) (*model.Bot, *model.AppError) {
|
||||
origCtx := a.ctx
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.ConvertUserToBot")
|
||||
|
||||
@ -1896,7 +1896,7 @@ func (a *OpenTracingAppLayer) ConvertUserToBot(user *model.User) (*model.Bot, *m
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
resultVar0, resultVar1 := a.app.ConvertUserToBot(user)
|
||||
resultVar0, resultVar1 := a.app.ConvertUserToBot(rctx, user)
|
||||
|
||||
if resultVar1 != nil {
|
||||
span.LogFields(spanlog.Error(resultVar1))
|
||||
@ -1950,7 +1950,7 @@ func (a *OpenTracingAppLayer) CopyWranglerPostlist(c request.CTX, wpl *model.Wra
|
||||
return resultVar0, resultVar1
|
||||
}
|
||||
|
||||
func (a *OpenTracingAppLayer) CreateBot(c request.CTX, bot *model.Bot) (*model.Bot, *model.AppError) {
|
||||
func (a *OpenTracingAppLayer) CreateBot(rctx request.CTX, bot *model.Bot) (*model.Bot, *model.AppError) {
|
||||
origCtx := a.ctx
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.CreateBot")
|
||||
|
||||
@ -1962,7 +1962,7 @@ func (a *OpenTracingAppLayer) CreateBot(c request.CTX, bot *model.Bot) (*model.B
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
resultVar0, resultVar1 := a.app.CreateBot(c, bot)
|
||||
resultVar0, resultVar1 := a.app.CreateBot(rctx, bot)
|
||||
|
||||
if resultVar1 != nil {
|
||||
span.LogFields(spanlog.Error(resultVar1))
|
||||
@ -5006,7 +5006,7 @@ func (a *OpenTracingAppLayer) GetAllTeamsPageWithCount(offset int, limit int, op
|
||||
return resultVar0, resultVar1
|
||||
}
|
||||
|
||||
func (a *OpenTracingAppLayer) GetAnalytics(name string, teamID string) (model.AnalyticsRows, *model.AppError) {
|
||||
func (a *OpenTracingAppLayer) GetAnalytics(rctx request.CTX, name string, teamID string) (model.AnalyticsRows, *model.AppError) {
|
||||
origCtx := a.ctx
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetAnalytics")
|
||||
|
||||
@ -5018,7 +5018,7 @@ func (a *OpenTracingAppLayer) GetAnalytics(name string, teamID string) (model.An
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
resultVar0, resultVar1 := a.app.GetAnalytics(name, teamID)
|
||||
resultVar0, resultVar1 := a.app.GetAnalytics(rctx, name, teamID)
|
||||
|
||||
if resultVar1 != nil {
|
||||
span.LogFields(spanlog.Error(resultVar1))
|
||||
@ -5138,7 +5138,7 @@ func (a *OpenTracingAppLayer) GetAuthorizedAppsForUser(userID string, page int,
|
||||
return resultVar0, resultVar1
|
||||
}
|
||||
|
||||
func (a *OpenTracingAppLayer) GetBot(botUserId string, includeDeleted bool) (*model.Bot, *model.AppError) {
|
||||
func (a *OpenTracingAppLayer) GetBot(rctx request.CTX, botUserId string, includeDeleted bool) (*model.Bot, *model.AppError) {
|
||||
origCtx := a.ctx
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetBot")
|
||||
|
||||
@ -5150,7 +5150,7 @@ func (a *OpenTracingAppLayer) GetBot(botUserId string, includeDeleted bool) (*mo
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
resultVar0, resultVar1 := a.app.GetBot(botUserId, includeDeleted)
|
||||
resultVar0, resultVar1 := a.app.GetBot(rctx, botUserId, includeDeleted)
|
||||
|
||||
if resultVar1 != nil {
|
||||
span.LogFields(spanlog.Error(resultVar1))
|
||||
@ -5160,7 +5160,7 @@ func (a *OpenTracingAppLayer) GetBot(botUserId string, includeDeleted bool) (*mo
|
||||
return resultVar0, resultVar1
|
||||
}
|
||||
|
||||
func (a *OpenTracingAppLayer) GetBots(options *model.BotGetOptions) (model.BotList, *model.AppError) {
|
||||
func (a *OpenTracingAppLayer) GetBots(rctx request.CTX, options *model.BotGetOptions) (model.BotList, *model.AppError) {
|
||||
origCtx := a.ctx
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetBots")
|
||||
|
||||
@ -5172,7 +5172,7 @@ func (a *OpenTracingAppLayer) GetBots(options *model.BotGetOptions) (model.BotLi
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
resultVar0, resultVar1 := a.app.GetBots(options)
|
||||
resultVar0, resultVar1 := a.app.GetBots(rctx, options)
|
||||
|
||||
if resultVar1 != nil {
|
||||
span.LogFields(spanlog.Error(resultVar1))
|
||||
@ -7440,7 +7440,7 @@ func (a *OpenTracingAppLayer) GetMultipleEmojiByName(c request.CTX, names []stri
|
||||
return resultVar0, resultVar1
|
||||
}
|
||||
|
||||
func (a *OpenTracingAppLayer) GetNewUsersForTeamPage(teamID string, page int, perPage int, asAdmin bool, viewRestrictions *model.ViewUsersRestrictions) ([]*model.User, *model.AppError) {
|
||||
func (a *OpenTracingAppLayer) GetNewUsersForTeamPage(rctx request.CTX, teamID string, page int, perPage int, asAdmin bool, viewRestrictions *model.ViewUsersRestrictions) ([]*model.User, *model.AppError) {
|
||||
origCtx := a.ctx
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetNewUsersForTeamPage")
|
||||
|
||||
@ -7452,7 +7452,7 @@ func (a *OpenTracingAppLayer) GetNewUsersForTeamPage(teamID string, page int, pe
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
resultVar0, resultVar1 := a.app.GetNewUsersForTeamPage(teamID, page, perPage, asAdmin, viewRestrictions)
|
||||
resultVar0, resultVar1 := a.app.GetNewUsersForTeamPage(rctx, teamID, page, perPage, asAdmin, viewRestrictions)
|
||||
|
||||
if resultVar1 != nil {
|
||||
span.LogFields(spanlog.Error(resultVar1))
|
||||
@ -8779,7 +8779,7 @@ func (a *OpenTracingAppLayer) GetReactionsForPost(postID string) ([]*model.React
|
||||
return resultVar0, resultVar1
|
||||
}
|
||||
|
||||
func (a *OpenTracingAppLayer) GetRecentlyActiveUsersForTeam(teamID string) (map[string]*model.User, *model.AppError) {
|
||||
func (a *OpenTracingAppLayer) GetRecentlyActiveUsersForTeam(rctx request.CTX, teamID string) (map[string]*model.User, *model.AppError) {
|
||||
origCtx := a.ctx
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetRecentlyActiveUsersForTeam")
|
||||
|
||||
@ -8791,7 +8791,7 @@ func (a *OpenTracingAppLayer) GetRecentlyActiveUsersForTeam(teamID string) (map[
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
resultVar0, resultVar1 := a.app.GetRecentlyActiveUsersForTeam(teamID)
|
||||
resultVar0, resultVar1 := a.app.GetRecentlyActiveUsersForTeam(rctx, teamID)
|
||||
|
||||
if resultVar1 != nil {
|
||||
span.LogFields(spanlog.Error(resultVar1))
|
||||
@ -8801,7 +8801,7 @@ func (a *OpenTracingAppLayer) GetRecentlyActiveUsersForTeam(teamID string) (map[
|
||||
return resultVar0, resultVar1
|
||||
}
|
||||
|
||||
func (a *OpenTracingAppLayer) GetRecentlyActiveUsersForTeamPage(teamID string, page int, perPage int, asAdmin bool, viewRestrictions *model.ViewUsersRestrictions) ([]*model.User, *model.AppError) {
|
||||
func (a *OpenTracingAppLayer) GetRecentlyActiveUsersForTeamPage(rctx request.CTX, teamID string, page int, perPage int, asAdmin bool, viewRestrictions *model.ViewUsersRestrictions) ([]*model.User, *model.AppError) {
|
||||
origCtx := a.ctx
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetRecentlyActiveUsersForTeamPage")
|
||||
|
||||
@ -8813,7 +8813,7 @@ func (a *OpenTracingAppLayer) GetRecentlyActiveUsersForTeamPage(teamID string, p
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
resultVar0, resultVar1 := a.app.GetRecentlyActiveUsersForTeamPage(teamID, page, perPage, asAdmin, viewRestrictions)
|
||||
resultVar0, resultVar1 := a.app.GetRecentlyActiveUsersForTeamPage(rctx, teamID, page, perPage, asAdmin, viewRestrictions)
|
||||
|
||||
if resultVar1 != nil {
|
||||
span.LogFields(spanlog.Error(resultVar1))
|
||||
@ -13276,7 +13276,7 @@ func (a *OpenTracingAppLayer) PermanentDeleteAllUsers(c request.CTX) *model.AppE
|
||||
return resultVar0
|
||||
}
|
||||
|
||||
func (a *OpenTracingAppLayer) PermanentDeleteBot(botUserId string) *model.AppError {
|
||||
func (a *OpenTracingAppLayer) PermanentDeleteBot(rctx request.CTX, botUserId string) *model.AppError {
|
||||
origCtx := a.ctx
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.PermanentDeleteBot")
|
||||
|
||||
@ -13288,7 +13288,7 @@ func (a *OpenTracingAppLayer) PermanentDeleteBot(botUserId string) *model.AppErr
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
resultVar0 := a.app.PermanentDeleteBot(botUserId)
|
||||
resultVar0 := a.app.PermanentDeleteBot(rctx, botUserId)
|
||||
|
||||
if resultVar0 != nil {
|
||||
span.LogFields(spanlog.Error(resultVar0))
|
||||
@ -16150,7 +16150,7 @@ func (a *OpenTracingAppLayer) SessionHasPermissionToGroup(session model.Session,
|
||||
return resultVar0
|
||||
}
|
||||
|
||||
func (a *OpenTracingAppLayer) SessionHasPermissionToManageBot(session model.Session, botUserId string) *model.AppError {
|
||||
func (a *OpenTracingAppLayer) SessionHasPermissionToManageBot(rctx request.CTX, session model.Session, botUserId string) *model.AppError {
|
||||
origCtx := a.ctx
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.SessionHasPermissionToManageBot")
|
||||
|
||||
@ -16162,7 +16162,7 @@ func (a *OpenTracingAppLayer) SessionHasPermissionToManageBot(session model.Sess
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
resultVar0 := a.app.SessionHasPermissionToManageBot(session, botUserId)
|
||||
resultVar0 := a.app.SessionHasPermissionToManageBot(rctx, session, botUserId)
|
||||
|
||||
if resultVar0 != nil {
|
||||
span.LogFields(spanlog.Error(resultVar0))
|
||||
@ -16240,7 +16240,7 @@ func (a *OpenTracingAppLayer) SessionHasPermissionToUser(session model.Session,
|
||||
return resultVar0
|
||||
}
|
||||
|
||||
func (a *OpenTracingAppLayer) SessionHasPermissionToUserOrBot(session model.Session, userID string) bool {
|
||||
func (a *OpenTracingAppLayer) SessionHasPermissionToUserOrBot(rctx request.CTX, session model.Session, userID string) bool {
|
||||
origCtx := a.ctx
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.SessionHasPermissionToUserOrBot")
|
||||
|
||||
@ -16252,7 +16252,7 @@ func (a *OpenTracingAppLayer) SessionHasPermissionToUserOrBot(session model.Sess
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
resultVar0 := a.app.SessionHasPermissionToUserOrBot(session, userID)
|
||||
resultVar0 := a.app.SessionHasPermissionToUserOrBot(rctx, session, userID)
|
||||
|
||||
return resultVar0
|
||||
}
|
||||
@ -17496,7 +17496,7 @@ func (a *OpenTracingAppLayer) UpdateActive(c request.CTX, user *model.User, acti
|
||||
return resultVar0, resultVar1
|
||||
}
|
||||
|
||||
func (a *OpenTracingAppLayer) UpdateBotActive(c request.CTX, botUserId string, active bool) (*model.Bot, *model.AppError) {
|
||||
func (a *OpenTracingAppLayer) UpdateBotActive(rctx request.CTX, botUserId string, active bool) (*model.Bot, *model.AppError) {
|
||||
origCtx := a.ctx
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.UpdateBotActive")
|
||||
|
||||
@ -17508,7 +17508,7 @@ func (a *OpenTracingAppLayer) UpdateBotActive(c request.CTX, botUserId string, a
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
resultVar0, resultVar1 := a.app.UpdateBotActive(c, botUserId, active)
|
||||
resultVar0, resultVar1 := a.app.UpdateBotActive(rctx, botUserId, active)
|
||||
|
||||
if resultVar1 != nil {
|
||||
span.LogFields(spanlog.Error(resultVar1))
|
||||
@ -17518,7 +17518,7 @@ func (a *OpenTracingAppLayer) UpdateBotActive(c request.CTX, botUserId string, a
|
||||
return resultVar0, resultVar1
|
||||
}
|
||||
|
||||
func (a *OpenTracingAppLayer) UpdateBotOwner(botUserId string, newOwnerId string) (*model.Bot, *model.AppError) {
|
||||
func (a *OpenTracingAppLayer) UpdateBotOwner(rctx request.CTX, botUserId string, newOwnerId string) (*model.Bot, *model.AppError) {
|
||||
origCtx := a.ctx
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.UpdateBotOwner")
|
||||
|
||||
@ -17530,7 +17530,7 @@ func (a *OpenTracingAppLayer) UpdateBotOwner(botUserId string, newOwnerId string
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
resultVar0, resultVar1 := a.app.UpdateBotOwner(botUserId, newOwnerId)
|
||||
resultVar0, resultVar1 := a.app.UpdateBotOwner(rctx, botUserId, newOwnerId)
|
||||
|
||||
if resultVar1 != nil {
|
||||
span.LogFields(spanlog.Error(resultVar1))
|
||||
|
@ -1027,11 +1027,11 @@ func (api *PluginAPI) PatchBot(userID string, botPatch *model.BotPatch) (*model.
|
||||
}
|
||||
|
||||
func (api *PluginAPI) GetBot(userID string, includeDeleted bool) (*model.Bot, *model.AppError) {
|
||||
return api.app.GetBot(userID, includeDeleted)
|
||||
return api.app.GetBot(api.ctx, userID, includeDeleted)
|
||||
}
|
||||
|
||||
func (api *PluginAPI) GetBots(options *model.BotGetOptions) ([]*model.Bot, *model.AppError) {
|
||||
bots, err := api.app.GetBots(options)
|
||||
bots, err := api.app.GetBots(api.ctx, options)
|
||||
|
||||
return []*model.Bot(bots), err
|
||||
}
|
||||
@ -1041,7 +1041,7 @@ func (api *PluginAPI) UpdateBotActive(userID string, active bool) (*model.Bot, *
|
||||
}
|
||||
|
||||
func (api *PluginAPI) PermanentDeleteBot(userID string) *model.AppError {
|
||||
return api.app.PermanentDeleteBot(userID)
|
||||
return api.app.PermanentDeleteBot(api.ctx, userID)
|
||||
}
|
||||
|
||||
func (api *PluginAPI) EnsureBotUser(bot *model.Bot) (string, error) {
|
||||
|
@ -203,7 +203,7 @@ func (a *App) generateSupportPacketYaml(c request.CTX) (*model.FileData, error)
|
||||
|
||||
/* Server stats */
|
||||
|
||||
analytics, appErr := a.GetAnalytics("standard", "")
|
||||
analytics, appErr := a.GetAnalytics(c, "standard", "")
|
||||
if appErr != nil {
|
||||
rErr = multierror.Append(errors.Wrap(appErr, "error while getting analytics"))
|
||||
}
|
||||
|
@ -263,9 +263,15 @@ func (a *App) createUserOrGuest(c request.CTX, user *model.User, guest bool) (*m
|
||||
}
|
||||
}
|
||||
|
||||
if user.EmailVerified {
|
||||
a.InvalidateCacheForUser(ruser.Id)
|
||||
// We always invalidate the user because we actually need to invalidate
|
||||
// in case the user's EmailVerified is true, but we also always need to invalidate
|
||||
// the GetAllProfiles cache.
|
||||
// To have a proper fix would mean duplicating the invalidation of GetAllProfiles
|
||||
// everywhere else. Therefore, to keep things simple we always invalidate both caches here.
|
||||
// The performance penalty for invalidating the UserById cache is nil because the user was just created.
|
||||
a.InvalidateCacheForUser(ruser.Id)
|
||||
|
||||
if user.EmailVerified {
|
||||
nUser, err := a.ch.srv.userService.GetUser(ruser.Id)
|
||||
if err != nil {
|
||||
var nfErr *store.ErrNotFound
|
||||
|
@ -353,7 +353,7 @@ func TestUpdateActiveBotsSideEffect(t *testing.T) {
|
||||
OwnerId: th.BasicUser.Id,
|
||||
})
|
||||
require.Nil(t, err)
|
||||
defer th.App.PermanentDeleteBot(bot.UserId)
|
||||
defer th.App.PermanentDeleteBot(th.Context, bot.UserId)
|
||||
|
||||
// Automatic deactivation disabled
|
||||
th.App.UpdateConfig(func(cfg *model.Config) {
|
||||
@ -362,7 +362,7 @@ func TestUpdateActiveBotsSideEffect(t *testing.T) {
|
||||
|
||||
th.App.UpdateActive(th.Context, th.BasicUser, false)
|
||||
|
||||
retbot1, err := th.App.GetBot(bot.UserId, true)
|
||||
retbot1, err := th.App.GetBot(th.Context, bot.UserId, true)
|
||||
require.Nil(t, err)
|
||||
require.Zero(t, retbot1.DeleteAt)
|
||||
user1, err := th.App.GetUser(bot.UserId)
|
||||
@ -378,7 +378,7 @@ func TestUpdateActiveBotsSideEffect(t *testing.T) {
|
||||
|
||||
th.App.UpdateActive(th.Context, th.BasicUser, false)
|
||||
|
||||
retbot2, err := th.App.GetBot(bot.UserId, true)
|
||||
retbot2, err := th.App.GetBot(th.Context, bot.UserId, true)
|
||||
require.Nil(t, err)
|
||||
require.NotZero(t, retbot2.DeleteAt)
|
||||
user2, err := th.App.GetUser(bot.UserId)
|
||||
|
@ -442,7 +442,7 @@ func TestRestrictedViewMembers(t *testing.T) {
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.Name, func(t *testing.T) {
|
||||
results, err := th.App.GetNewUsersForTeamPage(tc.TeamId, 0, 2, false, tc.Restrictions)
|
||||
results, err := th.App.GetNewUsersForTeamPage(th.Context, tc.TeamId, 0, 2, false, tc.Restrictions)
|
||||
require.Nil(t, err)
|
||||
ids := []string{}
|
||||
for _, result := range results {
|
||||
@ -517,7 +517,7 @@ func TestRestrictedViewMembers(t *testing.T) {
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.Name, func(t *testing.T) {
|
||||
results, err := th.App.GetRecentlyActiveUsersForTeamPage(tc.TeamId, 0, 3, false, tc.Restrictions)
|
||||
results, err := th.App.GetRecentlyActiveUsersForTeamPage(th.Context, tc.TeamId, 0, 3, false, tc.Restrictions)
|
||||
require.Nil(t, err)
|
||||
ids := []string{}
|
||||
for _, result := range results {
|
||||
@ -525,7 +525,7 @@ func TestRestrictedViewMembers(t *testing.T) {
|
||||
}
|
||||
assert.ElementsMatch(t, tc.ExpectedResults, ids)
|
||||
|
||||
results, err = th.App.GetRecentlyActiveUsersForTeamPage(tc.TeamId, 0, 1, false, tc.Restrictions)
|
||||
results, err = th.App.GetRecentlyActiveUsersForTeamPage(th.Context, tc.TeamId, 0, 1, false, tc.Restrictions)
|
||||
require.Nil(t, err)
|
||||
if len(tc.ExpectedResults) > 1 {
|
||||
assert.Len(t, results, 1)
|
||||
|
@ -112,6 +112,7 @@ type LocalCacheStore struct {
|
||||
postsUsageCache cache.Cache
|
||||
|
||||
user *LocalCacheUserStore
|
||||
allUserCache cache.Cache
|
||||
userProfileByIdsCache cache.Cache
|
||||
profilesInChannelCache cache.Cache
|
||||
|
||||
@ -315,6 +316,14 @@ func NewLocalCacheLayer(baseStore store.Store, metrics einterfaces.MetricsInterf
|
||||
localCacheStore.termsOfService = LocalCacheTermsOfServiceStore{TermsOfServiceStore: baseStore.TermsOfService(), rootStore: &localCacheStore}
|
||||
|
||||
// Users
|
||||
if localCacheStore.allUserCache, err = cacheProvider.NewCache(&cache.CacheOptions{
|
||||
Size: 1,
|
||||
Name: "AllUserProfiles",
|
||||
DefaultExpiry: UserProfileByIDSec * time.Second,
|
||||
InvalidateClusterEvent: model.ClusterEventInvalidateCacheForAllProfiles,
|
||||
}); err != nil {
|
||||
return
|
||||
}
|
||||
if localCacheStore.userProfileByIdsCache, err = cacheProvider.NewCache(&cache.CacheOptions{
|
||||
Size: UserProfileByIDCacheSize,
|
||||
Name: "UserProfileByIds",
|
||||
@ -372,6 +381,7 @@ func NewLocalCacheLayer(baseStore store.Store, metrics einterfaces.MetricsInterf
|
||||
cluster.RegisterClusterMessageHandler(model.ClusterEventInvalidateCacheForTermsOfService, localCacheStore.termsOfService.handleClusterInvalidateTermsOfService)
|
||||
cluster.RegisterClusterMessageHandler(model.ClusterEventInvalidateCacheForProfileByIds, localCacheStore.user.handleClusterInvalidateScheme)
|
||||
cluster.RegisterClusterMessageHandler(model.ClusterEventInvalidateCacheForProfileInChannel, localCacheStore.user.handleClusterInvalidateProfilesInChannel)
|
||||
cluster.RegisterClusterMessageHandler(model.ClusterEventInvalidateCacheForAllProfiles, localCacheStore.user.handleClusterInvalidateAllProfiles)
|
||||
cluster.RegisterClusterMessageHandler(model.ClusterEventInvalidateCacheForTeams, localCacheStore.team.handleClusterInvalidateTeam)
|
||||
}
|
||||
return
|
||||
@ -497,6 +507,7 @@ func (s *LocalCacheStore) Invalidate() {
|
||||
s.doClearCacheCluster(s.termsOfServiceCache)
|
||||
s.doClearCacheCluster(s.lastPostTimeCache)
|
||||
s.doClearCacheCluster(s.userProfileByIdsCache)
|
||||
s.doClearCacheCluster(s.allUserCache)
|
||||
s.doClearCacheCluster(s.profilesInChannelCache)
|
||||
s.doClearCacheCluster(s.teamAllTeamIdsForUserCache)
|
||||
s.doClearCacheCluster(s.rolePermissionsCache)
|
||||
|
@ -157,6 +157,7 @@ func getMockStore(t *testing.T) *mocks.Store {
|
||||
}
|
||||
mockUserStore.On("GetAllProfilesInChannel", mock.Anything, "123", true).Return(fakeProfilesInChannelMap, nil)
|
||||
mockUserStore.On("GetAllProfilesInChannel", mock.Anything, "123", false).Return(fakeProfilesInChannelMap, nil)
|
||||
mockUserStore.On("GetAllProfiles", mock.AnythingOfType("*model.UserGetOptions")).Return(fakeUser, nil)
|
||||
|
||||
mockUserStore.On("Get", mock.Anything, "123").Return(fakeUser[0], nil)
|
||||
users := []*model.User{
|
||||
|
@ -21,6 +21,8 @@ type LocalCacheUserStore struct {
|
||||
userProfileByIdsInvalidations map[string]bool
|
||||
}
|
||||
|
||||
const allUserKey = "ALL"
|
||||
|
||||
func (s *LocalCacheUserStore) handleClusterInvalidateScheme(msg *model.ClusterMessage) {
|
||||
if bytes.Equal(msg.Data, clearCacheMessageData) {
|
||||
s.rootStore.userProfileByIdsCache.Purge()
|
||||
@ -40,8 +42,17 @@ func (s *LocalCacheUserStore) handleClusterInvalidateProfilesInChannel(msg *mode
|
||||
}
|
||||
}
|
||||
|
||||
func (s *LocalCacheUserStore) handleClusterInvalidateAllProfiles(msg *model.ClusterMessage) {
|
||||
if bytes.Equal(msg.Data, clearCacheMessageData) {
|
||||
s.rootStore.allUserCache.Purge()
|
||||
} else {
|
||||
s.rootStore.allUserCache.Remove(string(msg.Data))
|
||||
}
|
||||
}
|
||||
|
||||
func (s *LocalCacheUserStore) ClearCaches() {
|
||||
s.rootStore.userProfileByIdsCache.Purge()
|
||||
s.rootStore.allUserCache.Purge()
|
||||
s.rootStore.profilesInChannelCache.Purge()
|
||||
|
||||
if s.rootStore.metrics != nil {
|
||||
@ -55,6 +66,7 @@ func (s *LocalCacheUserStore) InvalidateProfileCacheForUser(userId string) {
|
||||
s.userProfileByIdsInvalidations[userId] = true
|
||||
s.userProfileByIdsMut.Unlock()
|
||||
s.rootStore.doInvalidateCacheCluster(s.rootStore.userProfileByIdsCache, userId, nil)
|
||||
s.rootStore.doInvalidateCacheCluster(s.rootStore.allUserCache, allUserKey, nil)
|
||||
|
||||
if s.rootStore.metrics != nil {
|
||||
s.rootStore.metrics.IncrementMemCacheInvalidationCounter("Profile By Ids - Remove")
|
||||
@ -85,6 +97,30 @@ func (s *LocalCacheUserStore) InvalidateProfilesInChannelCache(channelID string)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *LocalCacheUserStore) GetAllProfiles(options *model.UserGetOptions) ([]*model.User, error) {
|
||||
if isEmptyOptions(options) &&
|
||||
options.Page == 0 && options.PerPage == 100 { // This is hardcoded to the webapp call.
|
||||
// read from cache
|
||||
var users []*model.User
|
||||
if err := s.rootStore.doStandardReadCache(s.rootStore.allUserCache, allUserKey, &users); err == nil {
|
||||
return users, nil
|
||||
}
|
||||
|
||||
users, err := s.UserStore.GetAllProfiles(options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// populate the cache only for those options.
|
||||
s.rootStore.doStandardAddToCache(s.rootStore.allUserCache, allUserKey, users)
|
||||
|
||||
return users, nil
|
||||
}
|
||||
|
||||
// For any other case, simply use the store
|
||||
return s.UserStore.GetAllProfiles(options)
|
||||
}
|
||||
|
||||
func (s *LocalCacheUserStore) GetAllProfilesInChannel(ctx context.Context, channelId string, allowFromCache bool) (map[string]*model.User, error) {
|
||||
if allowFromCache {
|
||||
var cachedMap map[string]*model.User
|
||||
@ -261,3 +297,26 @@ func dedup(elements []string) []string {
|
||||
|
||||
return elements[:j+1]
|
||||
}
|
||||
|
||||
func isEmptyOptions(options *model.UserGetOptions) bool {
|
||||
// We check to see if any of the options are set or not, and then
|
||||
// use the cache only if none are set, which is the most common case.
|
||||
// options.WithoutTeam, Sort is unused
|
||||
if options.InTeamId == "" &&
|
||||
options.NotInTeamId == "" &&
|
||||
options.InChannelId == "" &&
|
||||
options.NotInChannelId == "" &&
|
||||
options.InGroupId == "" &&
|
||||
options.NotInGroupId == "" &&
|
||||
!options.GroupConstrained &&
|
||||
!options.Inactive &&
|
||||
!options.Active &&
|
||||
options.Role == "" &&
|
||||
len(options.Roles) == 0 &&
|
||||
len(options.ChannelRoles) == 0 &&
|
||||
len(options.TeamRoles) == 0 &&
|
||||
options.ViewRestrictions == nil {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
@ -118,6 +118,43 @@ func TestUserStoreCache(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestUserStoreGetAllProfiles(t *testing.T) {
|
||||
t.Run("first call not cached, second cached and returning same data", func(t *testing.T) {
|
||||
mockStore := getMockStore(t)
|
||||
mockCacheProvider := getMockCacheProvider()
|
||||
cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider)
|
||||
require.NoError(t, err)
|
||||
|
||||
users, err := cachedStore.User().GetAllProfiles(&model.UserGetOptions{Page: 0, PerPage: 100})
|
||||
require.NoError(t, err)
|
||||
mockStore.User().(*mocks.UserStore).AssertNumberOfCalls(t, "GetAllProfiles", 1)
|
||||
|
||||
users2, _ := cachedStore.User().GetAllProfiles(&model.UserGetOptions{Page: 0, PerPage: 100})
|
||||
mockStore.User().(*mocks.UserStore).AssertNumberOfCalls(t, "GetAllProfiles", 1)
|
||||
assert.Equal(t, users, users2)
|
||||
|
||||
_, _ = cachedStore.User().GetAllProfiles(&model.UserGetOptions{Page: 2, PerPage: 1})
|
||||
mockStore.User().(*mocks.UserStore).AssertNumberOfCalls(t, "GetAllProfiles", 2)
|
||||
assert.Equal(t, users, users2)
|
||||
})
|
||||
|
||||
t.Run("different page sizes aren't cached", func(t *testing.T) {
|
||||
mockStore := getMockStore(t)
|
||||
mockCacheProvider := getMockCacheProvider()
|
||||
cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, _ = cachedStore.User().GetAllProfiles(&model.UserGetOptions{Page: 0, PerPage: 100})
|
||||
mockStore.User().(*mocks.UserStore).AssertNumberOfCalls(t, "GetAllProfiles", 1)
|
||||
|
||||
_, _ = cachedStore.User().GetAllProfiles(&model.UserGetOptions{Page: 2, PerPage: 1})
|
||||
mockStore.User().(*mocks.UserStore).AssertNumberOfCalls(t, "GetAllProfiles", 2)
|
||||
|
||||
_, _ = cachedStore.User().GetAllProfiles(&model.UserGetOptions{Page: 1, PerPage: 2})
|
||||
mockStore.User().(*mocks.UserStore).AssertNumberOfCalls(t, "GetAllProfiles", 3)
|
||||
})
|
||||
}
|
||||
|
||||
func TestUserStoreProfilesInChannelCache(t *testing.T) {
|
||||
fakeChannelId := "123"
|
||||
fakeUserId := "456"
|
||||
|
@ -12,6 +12,8 @@ import (
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
sqlUtils "github.com/mattermost/mattermost/server/public/utils/sql"
|
||||
|
||||
"github.com/mattermost/mattermost/server/public/model"
|
||||
"github.com/mattermost/mattermost/server/public/shared/mlog"
|
||||
"github.com/mattermost/mattermost/server/v8/channels/db"
|
||||
@ -119,16 +121,16 @@ func (ss *SqlStore) initMorph(dryRun bool) (*morph.Morph, error) {
|
||||
var driver drivers.Driver
|
||||
switch ss.DriverName() {
|
||||
case model.DatabaseDriverMysql:
|
||||
dataSource, rErr := ResetReadTimeout(*ss.settings.DataSource)
|
||||
dataSource, rErr := sqlUtils.ResetReadTimeout(*ss.settings.DataSource)
|
||||
if rErr != nil {
|
||||
mlog.Fatal("Failed to reset read timeout from datasource.", mlog.Err(rErr), mlog.String("src", *ss.settings.DataSource))
|
||||
return nil, rErr
|
||||
}
|
||||
dataSource, err = AppendMultipleStatementsFlag(dataSource)
|
||||
dataSource, err = sqlUtils.AppendMultipleStatementsFlag(dataSource)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
db, err2 := SetupConnection(ss.Logger(), "master", dataSource, ss.settings, DBPingAttempts)
|
||||
db, err2 := sqlUtils.SetupConnection(ss.Logger(), "master", dataSource, ss.settings, DBPingAttempts)
|
||||
if err2 != nil {
|
||||
return nil, err2
|
||||
}
|
||||
|
@ -15,6 +15,8 @@ import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
sqlUtils "github.com/mattermost/mattermost/server/public/utils/sql"
|
||||
|
||||
sq "github.com/mattermost/squirrel"
|
||||
|
||||
"github.com/go-sql-driver/mysql"
|
||||
@ -44,7 +46,6 @@ const (
|
||||
PGDuplicateObjectErrorCode = "42710"
|
||||
MySQLDuplicateObjectErrorCode = 1022
|
||||
DBPingAttempts = 5
|
||||
DBPingTimeoutSecs = 10
|
||||
// This is a numerical version string by postgres. The format is
|
||||
// 2 characters for major, minor, and patch version prior to 10.
|
||||
// After 10, it's major and minor only.
|
||||
@ -241,58 +242,6 @@ func New(settings model.SqlSettings, logger mlog.LoggerIFace, metrics einterface
|
||||
return store, nil
|
||||
}
|
||||
|
||||
// SetupConnection sets up the connection to the database and pings it to make sure it's alive.
|
||||
// It also applies any database configuration settings that are required.
|
||||
func SetupConnection(logger mlog.LoggerIFace, connType string, dataSource string, settings *model.SqlSettings, attempts int) (*dbsql.DB, error) {
|
||||
db, err := dbsql.Open(*settings.DriverName, dataSource)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to open SQL connection")
|
||||
}
|
||||
|
||||
// At this point, we have passed sql.Open, so we deliberately ignore any errors.
|
||||
sanitized, _ := SanitizeDataSource(*settings.DriverName, dataSource)
|
||||
|
||||
logger = logger.With(
|
||||
mlog.String("database", connType),
|
||||
mlog.String("dataSource", sanitized),
|
||||
)
|
||||
|
||||
for i := 0; i < attempts; i++ {
|
||||
logger.Info("Pinging SQL")
|
||||
ctx, cancel := context.WithTimeout(context.Background(), DBPingTimeoutSecs*time.Second)
|
||||
defer cancel()
|
||||
err = db.PingContext(ctx)
|
||||
if err != nil {
|
||||
if i == attempts-1 {
|
||||
return nil, err
|
||||
}
|
||||
logger.Error("Failed to ping DB", mlog.Int("retrying in seconds", DBPingTimeoutSecs), mlog.Err(err))
|
||||
time.Sleep(DBPingTimeoutSecs * time.Second)
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
if strings.HasPrefix(connType, replicaLagPrefix) {
|
||||
// If this is a replica lag connection, we just open one connection.
|
||||
//
|
||||
// Arguably, if the query doesn't require a special credential, it does take up
|
||||
// one extra connection from the replica DB. But falling back to the replica
|
||||
// data source when the replica lag data source is null implies an ordering constraint
|
||||
// which makes things brittle and is not a good design.
|
||||
// If connections are an overhead, it is advised to use a connection pool.
|
||||
db.SetMaxOpenConns(1)
|
||||
db.SetMaxIdleConns(1)
|
||||
} else {
|
||||
db.SetMaxIdleConns(*settings.MaxIdleConns)
|
||||
db.SetMaxOpenConns(*settings.MaxOpenConns)
|
||||
}
|
||||
db.SetConnMaxLifetime(time.Duration(*settings.ConnMaxLifetimeMilliseconds) * time.Millisecond)
|
||||
db.SetConnMaxIdleTime(time.Duration(*settings.ConnMaxIdleTimeMilliseconds) * time.Millisecond)
|
||||
|
||||
return db, nil
|
||||
}
|
||||
|
||||
func (ss *SqlStore) SetContext(context context.Context) {
|
||||
ss.context = context
|
||||
}
|
||||
@ -314,13 +263,13 @@ func (ss *SqlStore) initConnection() error {
|
||||
// covers that already. Ideally we'd like to do this only for the upgrade
|
||||
// step. To be reviewed in MM-35789.
|
||||
var err error
|
||||
dataSource, err = ResetReadTimeout(dataSource)
|
||||
dataSource, err = sqlUtils.ResetReadTimeout(dataSource)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to reset read timeout from datasource")
|
||||
}
|
||||
}
|
||||
|
||||
handle, err := SetupConnection(ss.Logger(), "master", dataSource, ss.settings, DBPingAttempts)
|
||||
handle, err := sqlUtils.SetupConnection(ss.Logger(), "master", dataSource, ss.settings, DBPingAttempts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -338,7 +287,7 @@ func (ss *SqlStore) initConnection() error {
|
||||
ss.ReplicaXs = make([]*atomic.Pointer[sqlxDBWrapper], len(ss.settings.DataSourceReplicas))
|
||||
for i, replica := range ss.settings.DataSourceReplicas {
|
||||
ss.ReplicaXs[i] = &atomic.Pointer[sqlxDBWrapper]{}
|
||||
handle, err = SetupConnection(ss.Logger(), fmt.Sprintf("replica-%v", i), replica, ss.settings, DBPingAttempts)
|
||||
handle, err = sqlUtils.SetupConnection(ss.Logger(), fmt.Sprintf("replica-%v", i), replica, ss.settings, DBPingAttempts)
|
||||
if err != nil {
|
||||
// Initializing to be offline
|
||||
ss.ReplicaXs[i].Store(&sqlxDBWrapper{isOnline: &atomic.Bool{}})
|
||||
@ -353,7 +302,7 @@ func (ss *SqlStore) initConnection() error {
|
||||
ss.searchReplicaXs = make([]*atomic.Pointer[sqlxDBWrapper], len(ss.settings.DataSourceSearchReplicas))
|
||||
for i, replica := range ss.settings.DataSourceSearchReplicas {
|
||||
ss.searchReplicaXs[i] = &atomic.Pointer[sqlxDBWrapper]{}
|
||||
handle, err = SetupConnection(ss.Logger(), fmt.Sprintf("search-replica-%v", i), replica, ss.settings, DBPingAttempts)
|
||||
handle, err = sqlUtils.SetupConnection(ss.Logger(), fmt.Sprintf("search-replica-%v", i), replica, ss.settings, DBPingAttempts)
|
||||
if err != nil {
|
||||
// Initializing to be offline
|
||||
ss.searchReplicaXs[i].Store(&sqlxDBWrapper{isOnline: &atomic.Bool{}})
|
||||
@ -370,7 +319,7 @@ func (ss *SqlStore) initConnection() error {
|
||||
if src.DataSource == nil {
|
||||
continue
|
||||
}
|
||||
ss.replicaLagHandles[i], err = SetupConnection(ss.Logger(), fmt.Sprintf(replicaLagPrefix+"-%d", i), *src.DataSource, ss.settings, DBPingAttempts)
|
||||
ss.replicaLagHandles[i], err = sqlUtils.SetupConnection(ss.Logger(), fmt.Sprintf(replicaLagPrefix+"-%d", i), *src.DataSource, ss.settings, DBPingAttempts)
|
||||
if err != nil {
|
||||
mlog.Warn("Failed to setup replica lag handle. Skipping..", mlog.String("db", fmt.Sprintf(replicaLagPrefix+"-%d", i)), mlog.Err(err))
|
||||
continue
|
||||
@ -525,7 +474,7 @@ func (ss *SqlStore) monitorReplicas() {
|
||||
return
|
||||
}
|
||||
|
||||
handle, err := SetupConnection(ss.Logger(), name, dsn, ss.settings, 1)
|
||||
handle, err := sqlUtils.SetupConnection(ss.Logger(), name, dsn, ss.settings, 1)
|
||||
if err != nil {
|
||||
mlog.Warn("Failed to setup connection. Skipping..", mlog.String("db", name), mlog.Err(err))
|
||||
return
|
||||
|
@ -5,7 +5,6 @@ package sqlstore
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"io"
|
||||
"net/url"
|
||||
"strconv"
|
||||
@ -16,8 +15,6 @@ import (
|
||||
|
||||
"github.com/mattermost/mattermost/server/public/model"
|
||||
"github.com/mattermost/mattermost/server/public/shared/mlog"
|
||||
|
||||
"github.com/go-sql-driver/mysql"
|
||||
)
|
||||
|
||||
var escapeLikeSearchChar = []string{
|
||||
@ -183,57 +180,6 @@ func AppendBinaryFlag(buf []byte) []byte {
|
||||
return append([]byte{0x01}, buf...)
|
||||
}
|
||||
|
||||
// AppendMultipleStatementsFlag attached dsn parameters to MySQL dsn in order to make migrations work.
|
||||
func AppendMultipleStatementsFlag(dataSource string) (string, error) {
|
||||
config, err := mysql.ParseDSN(dataSource)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if config.Params == nil {
|
||||
config.Params = map[string]string{}
|
||||
}
|
||||
|
||||
config.Params["multiStatements"] = "true"
|
||||
return config.FormatDSN(), nil
|
||||
}
|
||||
|
||||
// ResetReadTimeout removes the timeout constraint from the MySQL dsn.
|
||||
func ResetReadTimeout(dataSource string) (string, error) {
|
||||
config, err := mysql.ParseDSN(dataSource)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
config.ReadTimeout = 0
|
||||
return config.FormatDSN(), nil
|
||||
}
|
||||
|
||||
func SanitizeDataSource(driverName, dataSource string) (string, error) {
|
||||
switch driverName {
|
||||
case model.DatabaseDriverPostgres:
|
||||
u, err := url.Parse(dataSource)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
u.User = url.UserPassword("****", "****")
|
||||
params := u.Query()
|
||||
params.Del("user")
|
||||
params.Del("password")
|
||||
u.RawQuery = params.Encode()
|
||||
return u.String(), nil
|
||||
case model.DatabaseDriverMysql:
|
||||
cfg, err := mysql.ParseDSN(dataSource)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
cfg.User = "****"
|
||||
cfg.Passwd = "****"
|
||||
return cfg.FormatDSN(), nil
|
||||
default:
|
||||
return "", errors.New("invalid drivername. Not postgres or mysql.")
|
||||
}
|
||||
}
|
||||
|
||||
const maxTokenSize = 50
|
||||
|
||||
// trimInput limits the string to a max size to prevent clogging up disk space
|
||||
|
@ -6,7 +6,6 @@ package sqlstore
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/mattermost/mattermost/server/public/model"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
@ -134,72 +133,3 @@ func TestMySQLJSONArgs(t *testing.T) {
|
||||
assert.Equal(t, test.argString, argString)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppendMultipleStatementsFlag(t *testing.T) {
|
||||
testCases := []struct {
|
||||
Scenario string
|
||||
DSN string
|
||||
ExpectedDSN string
|
||||
}{
|
||||
{
|
||||
"Should append multiStatements param to the DSN path with existing params",
|
||||
"user:rand?&ompasswith@character@unix(/var/run/mysqld/mysqld.sock)/mattermost?writeTimeout=30s",
|
||||
"user:rand?&ompasswith@character@unix(/var/run/mysqld/mysqld.sock)/mattermost?writeTimeout=30s&multiStatements=true",
|
||||
},
|
||||
{
|
||||
"Should append multiStatements param to the DSN path with no existing params",
|
||||
"user:rand?&ompasswith@character@unix(/var/run/mysqld/mysqld.sock)/mattermost",
|
||||
"user:rand?&ompasswith@character@unix(/var/run/mysqld/mysqld.sock)/mattermost?multiStatements=true",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.Scenario, func(t *testing.T) {
|
||||
res, err := AppendMultipleStatementsFlag(tc.DSN)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tc.ExpectedDSN, res)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSanitizeDataSource(t *testing.T) {
|
||||
t.Run(model.DatabaseDriverPostgres, func(t *testing.T) {
|
||||
testCases := []struct {
|
||||
Original string
|
||||
Sanitized string
|
||||
}{
|
||||
{
|
||||
"postgres://mmuser:mostest@localhost/dummy?sslmode=disable",
|
||||
"postgres://%2A%2A%2A%2A:%2A%2A%2A%2A@localhost/dummy?sslmode=disable",
|
||||
},
|
||||
{
|
||||
"postgres://localhost/dummy?sslmode=disable&user=mmuser&password=mostest",
|
||||
"postgres://%2A%2A%2A%2A:%2A%2A%2A%2A@localhost/dummy?sslmode=disable",
|
||||
},
|
||||
}
|
||||
driver := model.DatabaseDriverPostgres
|
||||
for _, tc := range testCases {
|
||||
out, err := SanitizeDataSource(driver, tc.Original)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tc.Sanitized, out)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run(model.DatabaseDriverMysql, func(t *testing.T) {
|
||||
testCases := []struct {
|
||||
Original string
|
||||
Sanitized string
|
||||
}{
|
||||
{
|
||||
"mmuser:mostest@tcp(localhost:3306)/mattermost_test?charset=utf8mb4,utf8&readTimeout=30s&writeTimeout=30s",
|
||||
"****:****@tcp(localhost:3306)/mattermost_test?readTimeout=30s&writeTimeout=30s&charset=utf8mb4%2Cutf8",
|
||||
},
|
||||
}
|
||||
driver := model.DatabaseDriverMysql
|
||||
for _, tc := range testCases {
|
||||
out, err := SanitizeDataSource(driver, tc.Original)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tc.Sanitized, out)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -22,14 +22,14 @@ func (s *MmctlE2ETestSuite) TestListBotCmdF() {
|
||||
bot, appErr := s.th.App.CreateBot(s.th.Context, &model.Bot{Username: model.NewId(), OwnerId: s.th.BasicUser.Id})
|
||||
s.Require().Nil(appErr)
|
||||
defer func() {
|
||||
err := s.th.App.PermanentDeleteBot(bot.UserId)
|
||||
err := s.th.App.PermanentDeleteBot(s.th.Context, bot.UserId)
|
||||
s.Require().Nil(err)
|
||||
}()
|
||||
|
||||
deletedBot, appErr := s.th.App.CreateBot(s.th.Context, &model.Bot{Username: model.NewId(), OwnerId: s.th.BasicUser.Id})
|
||||
s.Require().Nil(appErr)
|
||||
defer func() {
|
||||
err := s.th.App.PermanentDeleteBot(deletedBot.UserId)
|
||||
err := s.th.App.PermanentDeleteBot(s.th.Context, deletedBot.UserId)
|
||||
s.Require().Nil(err)
|
||||
}()
|
||||
|
||||
@ -59,14 +59,14 @@ func (s *MmctlE2ETestSuite) TestListBotCmdF() {
|
||||
bot, appErr := s.th.App.CreateBot(s.th.Context, &model.Bot{Username: model.NewId(), OwnerId: s.th.BasicUser.Id})
|
||||
s.Require().Nil(appErr)
|
||||
defer func() {
|
||||
err := s.th.App.PermanentDeleteBot(bot.UserId)
|
||||
err := s.th.App.PermanentDeleteBot(s.th.Context, bot.UserId)
|
||||
s.Require().Nil(err)
|
||||
}()
|
||||
|
||||
deletedBot, appErr := s.th.App.CreateBot(s.th.Context, &model.Bot{Username: model.NewId(), OwnerId: user.Id})
|
||||
s.Require().Nil(appErr)
|
||||
defer func() {
|
||||
err := s.th.App.PermanentDeleteBot(deletedBot.UserId)
|
||||
err := s.th.App.PermanentDeleteBot(s.th.Context, deletedBot.UserId)
|
||||
s.Require().Nil(err)
|
||||
}()
|
||||
|
||||
@ -76,7 +76,7 @@ func (s *MmctlE2ETestSuite) TestListBotCmdF() {
|
||||
orphanBot, appErr := s.th.App.CreateBot(s.th.Context, &model.Bot{Username: model.NewId(), OwnerId: user.Id})
|
||||
s.Require().Nil(appErr)
|
||||
defer func() {
|
||||
err := s.th.App.PermanentDeleteBot(orphanBot.UserId)
|
||||
err := s.th.App.PermanentDeleteBot(s.th.Context, orphanBot.UserId)
|
||||
s.Require().Nil(err)
|
||||
}()
|
||||
|
||||
@ -106,21 +106,21 @@ func (s *MmctlE2ETestSuite) TestListBotCmdF() {
|
||||
bot, appErr := s.th.App.CreateBot(s.th.Context, &model.Bot{Username: model.NewId(), OwnerId: s.th.BasicUser2.Id})
|
||||
s.Require().Nil(appErr)
|
||||
defer func() {
|
||||
err := s.th.App.PermanentDeleteBot(bot.UserId)
|
||||
err := s.th.App.PermanentDeleteBot(s.th.Context, bot.UserId)
|
||||
s.Require().Nil(err)
|
||||
}()
|
||||
|
||||
orphanBot, appErr := s.th.App.CreateBot(s.th.Context, &model.Bot{Username: model.NewId(), OwnerId: user.Id})
|
||||
s.Require().Nil(appErr)
|
||||
defer func() {
|
||||
err := s.th.App.PermanentDeleteBot(orphanBot.UserId)
|
||||
err := s.th.App.PermanentDeleteBot(s.th.Context, orphanBot.UserId)
|
||||
s.Require().Nil(err)
|
||||
}()
|
||||
|
||||
deletedBot, appErr := s.th.App.CreateBot(s.th.Context, &model.Bot{Username: model.NewId(), OwnerId: s.th.BasicUser2.Id})
|
||||
s.Require().Nil(appErr)
|
||||
defer func() {
|
||||
err := s.th.App.PermanentDeleteBot(deletedBot.UserId)
|
||||
err := s.th.App.PermanentDeleteBot(s.th.Context, deletedBot.UserId)
|
||||
s.Require().Nil(err)
|
||||
}()
|
||||
|
||||
@ -181,7 +181,7 @@ func (s *MmctlE2ETestSuite) TestBotEnableCmd() {
|
||||
s.Require().Equal(newBot.Username, printedBot.Username)
|
||||
s.Require().Equal(newBot.OwnerId, printedBot.OwnerId)
|
||||
|
||||
bot, appErr := s.th.App.GetBot(newBot.UserId, false)
|
||||
bot, appErr := s.th.App.GetBot(s.th.Context, newBot.UserId, false)
|
||||
s.Require().Nil(appErr)
|
||||
s.Require().Equal(newBot.UserId, bot.UserId)
|
||||
s.Require().Equal(newBot.Username, bot.Username)
|
||||
@ -235,7 +235,7 @@ func (s *MmctlE2ETestSuite) TestBotEnableCmd() {
|
||||
s.Require().Equal(newBot.Username, printedBot.Username)
|
||||
s.Require().Equal(newBot.OwnerId, printedBot.OwnerId)
|
||||
|
||||
bot, appErr := s.th.App.GetBot(newBot.UserId, false)
|
||||
bot, appErr := s.th.App.GetBot(s.th.Context, newBot.UserId, false)
|
||||
s.Require().Nil(appErr)
|
||||
s.Require().Equal(newBot.UserId, bot.UserId)
|
||||
s.Require().Equal(newBot.Username, bot.Username)
|
||||
@ -269,7 +269,7 @@ func (s *MmctlE2ETestSuite) TestBotDisableCmd() {
|
||||
s.Require().Equal(newBot.Username, printedBot.Username)
|
||||
s.Require().Equal(newBot.OwnerId, printedBot.OwnerId)
|
||||
|
||||
_, appErr = s.th.App.GetBot(newBot.UserId, false)
|
||||
_, appErr = s.th.App.GetBot(s.th.Context, newBot.UserId, false)
|
||||
s.Require().NotNil(appErr)
|
||||
s.Require().Equal("store.sql_bot.get.missing.app_error", appErr.Id)
|
||||
})
|
||||
@ -321,7 +321,7 @@ func (s *MmctlE2ETestSuite) TestBotDisableCmd() {
|
||||
s.Require().Equal(newBot.Username, printedBot.Username)
|
||||
s.Require().Equal(newBot.OwnerId, printedBot.OwnerId)
|
||||
|
||||
_, appErr = s.th.App.GetBot(newBot.UserId, false)
|
||||
_, appErr = s.th.App.GetBot(s.th.Context, newBot.UserId, false)
|
||||
s.Require().NotNil(appErr)
|
||||
s.Require().Equal("store.sql_bot.get.missing.app_error", appErr.Id)
|
||||
})
|
||||
@ -351,7 +351,7 @@ func (s *MmctlE2ETestSuite) TestBotAssignCmdF() {
|
||||
s.Require().Nil(appErr)
|
||||
s.Require().Equal(bot.OwnerId, botOwner.Id)
|
||||
defer func() {
|
||||
err := s.th.App.PermanentDeleteBot(bot.UserId)
|
||||
err := s.th.App.PermanentDeleteBot(s.th.Context, bot.UserId)
|
||||
s.Require().Nil(err)
|
||||
}()
|
||||
|
||||
@ -384,7 +384,7 @@ func (s *MmctlE2ETestSuite) TestBotAssignCmdF() {
|
||||
s.Require().Nil(appErr)
|
||||
s.Require().Equal(bot.OwnerId, botOwner.Id)
|
||||
defer func() {
|
||||
err := s.th.App.PermanentDeleteBot(bot.UserId)
|
||||
err := s.th.App.PermanentDeleteBot(s.th.Context, bot.UserId)
|
||||
s.Require().Nil(err)
|
||||
}()
|
||||
|
||||
@ -420,7 +420,7 @@ func (s *MmctlE2ETestSuite) TestBotCreateCmdF() {
|
||||
bot, ok := printer.GetLines()[0].(*model.Bot)
|
||||
s.Require().True(ok)
|
||||
defer func() {
|
||||
err := s.th.App.PermanentDeleteBot(bot.UserId)
|
||||
err := s.th.App.PermanentDeleteBot(s.th.Context, bot.UserId)
|
||||
s.Require().Nil(err)
|
||||
}()
|
||||
token, ok := printer.GetLines()[1].(*model.UserAccessToken)
|
||||
|
@ -15,6 +15,8 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
sqlUtils "github.com/mattermost/mattermost/server/public/utils/sql"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
@ -27,8 +29,6 @@ import (
|
||||
|
||||
"github.com/mattermost/mattermost/server/public/model"
|
||||
"github.com/mattermost/mattermost/server/public/shared/mlog"
|
||||
"github.com/mattermost/mattermost/server/v8/channels/store/sqlstore"
|
||||
|
||||
"github.com/mattermost/morph/drivers"
|
||||
ms "github.com/mattermost/morph/drivers/mysql"
|
||||
ps "github.com/mattermost/morph/drivers/postgres"
|
||||
@ -121,12 +121,12 @@ func (ds *DatabaseStore) initializeConfigurationsTable() error {
|
||||
var driver drivers.Driver
|
||||
switch ds.driverName {
|
||||
case model.DatabaseDriverMysql:
|
||||
dataSource, rErr := sqlstore.ResetReadTimeout(ds.dataSourceName)
|
||||
dataSource, rErr := sqlUtils.ResetReadTimeout(ds.dataSourceName)
|
||||
if rErr != nil {
|
||||
return fmt.Errorf("failed to reset read timeout from datasource: %w", rErr)
|
||||
}
|
||||
|
||||
dataSource, err = sqlstore.AppendMultipleStatementsFlag(dataSource)
|
||||
dataSource, err = sqlUtils.AppendMultipleStatementsFlag(dataSource)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -409,7 +409,7 @@ func (ds *DatabaseStore) RemoveFile(name string) error {
|
||||
func (ds *DatabaseStore) String() string {
|
||||
// This is called during the running of MM, so we expect the parsing of DSN
|
||||
// to be successful.
|
||||
sanitized, _ := sqlstore.SanitizeDataSource(ds.driverName, ds.originalDsn)
|
||||
sanitized, _ := sqlUtils.SanitizeDataSource(ds.driverName, ds.originalDsn)
|
||||
return sanitized
|
||||
}
|
||||
|
||||
|
@ -7932,7 +7932,7 @@
|
||||
},
|
||||
{
|
||||
"id": "ent.ldap.syncronize.search_failure_size_exceeded.app_error",
|
||||
"translation": "Size Limit Exceeded. Try checking your [max page size](https://docs.mattermost.com/deployment/sso-ldap.html#i-see-the-log-error-ldap-result-code-4-size-limit-exceeded)."
|
||||
"translation": "Size Limit Exceeded. Try increasing your Maximum page size setting. Check out https://docs.mattermost.com/onboard/ad-ldap.html#i-see-the-log-error-ldap-result-code-4-size-limit-exceeded for more details."
|
||||
},
|
||||
{
|
||||
"id": "ent.ldap.validate_admin_filter.app_error",
|
||||
|
@ -20,6 +20,7 @@ const (
|
||||
ClusterEventInvalidateCacheForRoles ClusterEvent = "inv_roles"
|
||||
ClusterEventInvalidateCacheForRolePermissions ClusterEvent = "inv_role_permissions"
|
||||
ClusterEventInvalidateCacheForProfileByIds ClusterEvent = "inv_profile_ids"
|
||||
ClusterEventInvalidateCacheForAllProfiles ClusterEvent = "inv_all_profiles"
|
||||
ClusterEventInvalidateCacheForProfileInChannel ClusterEvent = "inv_profile_in_channel"
|
||||
ClusterEventInvalidateCacheForSchemes ClusterEvent = "inv_schemes"
|
||||
ClusterEventInvalidateCacheForFileInfos ClusterEvent = "inv_file_infos"
|
||||
|
126
server/public/utils/sql/sql_utils.go
Normal file
126
server/public/utils/sql/sql_utils.go
Normal file
@ -0,0 +1,126 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package sql
|
||||
|
||||
import (
|
||||
"context"
|
||||
dbsql "database/sql"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-sql-driver/mysql"
|
||||
"github.com/mattermost/mattermost/server/public/model"
|
||||
"github.com/mattermost/mattermost/server/public/shared/mlog"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
DBPingTimeoutSecs = 10
|
||||
|
||||
replicaLagPrefix = "replica-lag"
|
||||
)
|
||||
|
||||
// ResetReadTimeout removes the timeout constraint from the MySQL dsn.
|
||||
func ResetReadTimeout(dataSource string) (string, error) {
|
||||
config, err := mysql.ParseDSN(dataSource)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
config.ReadTimeout = 0
|
||||
return config.FormatDSN(), nil
|
||||
}
|
||||
|
||||
// AppendMultipleStatementsFlag attached dsn parameters to MySQL dsn in order to make migrations work.
|
||||
func AppendMultipleStatementsFlag(dataSource string) (string, error) {
|
||||
config, err := mysql.ParseDSN(dataSource)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if config.Params == nil {
|
||||
config.Params = map[string]string{}
|
||||
}
|
||||
|
||||
config.Params["multiStatements"] = "true"
|
||||
return config.FormatDSN(), nil
|
||||
}
|
||||
|
||||
// SetupConnection sets up the connection to the database and pings it to make sure it's alive.
|
||||
// It also applies any database configuration settings that are required.
|
||||
func SetupConnection(logger mlog.LoggerIFace, connType string, dataSource string, settings *model.SqlSettings, attempts int) (*dbsql.DB, error) {
|
||||
db, err := dbsql.Open(*settings.DriverName, dataSource)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to open SQL connection")
|
||||
}
|
||||
|
||||
// At this point, we have passed sql.Open, so we deliberately ignore any errors.
|
||||
sanitized, _ := SanitizeDataSource(*settings.DriverName, dataSource)
|
||||
|
||||
logger = logger.With(
|
||||
mlog.String("database", connType),
|
||||
mlog.String("dataSource", sanitized),
|
||||
)
|
||||
|
||||
for i := 0; i < attempts; i++ {
|
||||
logger.Info("Pinging SQL")
|
||||
ctx, cancel := context.WithTimeout(context.Background(), DBPingTimeoutSecs*time.Second)
|
||||
defer cancel()
|
||||
err = db.PingContext(ctx)
|
||||
if err != nil {
|
||||
if i == attempts-1 {
|
||||
return nil, err
|
||||
}
|
||||
logger.Error("Failed to ping DB", mlog.Int("retrying in seconds", DBPingTimeoutSecs), mlog.Err(err))
|
||||
time.Sleep(DBPingTimeoutSecs * time.Second)
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
if strings.HasPrefix(connType, replicaLagPrefix) {
|
||||
// If this is a replica lag connection, we just open one connection.
|
||||
//
|
||||
// Arguably, if the query doesn't require a special credential, it does take up
|
||||
// one extra connection from the replica DB. But falling back to the replica
|
||||
// data source when the replica lag data source is null implies an ordering constraint
|
||||
// which makes things brittle and is not a good design.
|
||||
// If connections are an overhead, it is advised to use a connection pool.
|
||||
db.SetMaxOpenConns(1)
|
||||
db.SetMaxIdleConns(1)
|
||||
} else {
|
||||
db.SetMaxIdleConns(*settings.MaxIdleConns)
|
||||
db.SetMaxOpenConns(*settings.MaxOpenConns)
|
||||
}
|
||||
db.SetConnMaxLifetime(time.Duration(*settings.ConnMaxLifetimeMilliseconds) * time.Millisecond)
|
||||
db.SetConnMaxIdleTime(time.Duration(*settings.ConnMaxIdleTimeMilliseconds) * time.Millisecond)
|
||||
|
||||
return db, nil
|
||||
}
|
||||
|
||||
func SanitizeDataSource(driverName, dataSource string) (string, error) {
|
||||
switch driverName {
|
||||
case model.DatabaseDriverPostgres:
|
||||
u, err := url.Parse(dataSource)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
u.User = url.UserPassword("****", "****")
|
||||
params := u.Query()
|
||||
params.Del("user")
|
||||
params.Del("password")
|
||||
u.RawQuery = params.Encode()
|
||||
return u.String(), nil
|
||||
case model.DatabaseDriverMysql:
|
||||
cfg, err := mysql.ParseDSN(dataSource)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
cfg.User = "****"
|
||||
cfg.Passwd = "****"
|
||||
return cfg.FormatDSN(), nil
|
||||
default:
|
||||
return "", errors.New("invalid drivername. Not postgres or mysql.")
|
||||
}
|
||||
}
|
109
server/public/utils/sql/sql_utils_test.go
Normal file
109
server/public/utils/sql/sql_utils_test.go
Normal file
@ -0,0 +1,109 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package sql
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/mattermost/mattermost/server/public/model"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestAppendMultipleStatementsFlag(t *testing.T) {
|
||||
testCases := []struct {
|
||||
Scenario string
|
||||
DSN string
|
||||
ExpectedDSN string
|
||||
}{
|
||||
{
|
||||
"Should append multiStatements param to the DSN path with existing params",
|
||||
"user:rand?&ompasswith@character@unix(/var/run/mysqld/mysqld.sock)/mattermost?writeTimeout=30s",
|
||||
"user:rand?&ompasswith@character@unix(/var/run/mysqld/mysqld.sock)/mattermost?writeTimeout=30s&multiStatements=true",
|
||||
},
|
||||
{
|
||||
"Should append multiStatements param to the DSN path with no existing params",
|
||||
"user:rand?&ompasswith@character@unix(/var/run/mysqld/mysqld.sock)/mattermost",
|
||||
"user:rand?&ompasswith@character@unix(/var/run/mysqld/mysqld.sock)/mattermost?multiStatements=true",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.Scenario, func(t *testing.T) {
|
||||
res, err := AppendMultipleStatementsFlag(tc.DSN)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tc.ExpectedDSN, res)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestResetReadTimeout(t *testing.T) {
|
||||
testCases := []struct {
|
||||
Scenario string
|
||||
DSN string
|
||||
ExpectedDSN string
|
||||
}{
|
||||
{
|
||||
"Should re move read timeout param from the DSN",
|
||||
"user:rand?&ompasswith@character@unix(/var/run/mysqld/mysqld.sock)/mattermost?readTimeout=30s",
|
||||
"user:rand?&ompasswith@character@unix(/var/run/mysqld/mysqld.sock)/mattermost",
|
||||
},
|
||||
{
|
||||
"Should change nothing as there is no read timeout param specified",
|
||||
"user:rand?&ompasswith@character@unix(/var/run/mysqld/mysqld.sock)/mattermost",
|
||||
"user:rand?&ompasswith@character@unix(/var/run/mysqld/mysqld.sock)/mattermost",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.Scenario, func(t *testing.T) {
|
||||
res, err := ResetReadTimeout(tc.DSN)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tc.ExpectedDSN, res)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSanitizeDataSource(t *testing.T) {
|
||||
t.Run(model.DatabaseDriverPostgres, func(t *testing.T) {
|
||||
testCases := []struct {
|
||||
Original string
|
||||
Sanitized string
|
||||
}{
|
||||
{
|
||||
"postgres://mmuser:mostest@localhost/dummy?sslmode=disable",
|
||||
"postgres://%2A%2A%2A%2A:%2A%2A%2A%2A@localhost/dummy?sslmode=disable",
|
||||
},
|
||||
{
|
||||
"postgres://localhost/dummy?sslmode=disable&user=mmuser&password=mostest",
|
||||
"postgres://%2A%2A%2A%2A:%2A%2A%2A%2A@localhost/dummy?sslmode=disable",
|
||||
},
|
||||
}
|
||||
driver := model.DatabaseDriverPostgres
|
||||
for _, tc := range testCases {
|
||||
out, err := SanitizeDataSource(driver, tc.Original)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tc.Sanitized, out)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run(model.DatabaseDriverMysql, func(t *testing.T) {
|
||||
testCases := []struct {
|
||||
Original string
|
||||
Sanitized string
|
||||
}{
|
||||
{
|
||||
"mmuser:mostest@tcp(localhost:3306)/mattermost_test?charset=utf8mb4,utf8&readTimeout=30s&writeTimeout=30s",
|
||||
"****:****@tcp(localhost:3306)/mattermost_test?readTimeout=30s&writeTimeout=30s&charset=utf8mb4%2Cutf8",
|
||||
},
|
||||
}
|
||||
driver := model.DatabaseDriverMysql
|
||||
for _, tc := range testCases {
|
||||
out, err := SanitizeDataSource(driver, tc.Original)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tc.Sanitized, out)
|
||||
}
|
||||
})
|
||||
}
|
@ -77,6 +77,7 @@ exports[`components/admin_console/SchemaAdminSettings should match snapshot with
|
||||
isCurrentUserSystemAdmin={false}
|
||||
isDisabled={false}
|
||||
license={Object {}}
|
||||
patchConfig={[MockFunction]}
|
||||
roles={Object {}}
|
||||
schema={
|
||||
Object {
|
||||
@ -84,7 +85,6 @@ exports[`components/admin_console/SchemaAdminSettings should match snapshot with
|
||||
}
|
||||
}
|
||||
setNavigationBlocked={[MockFunction]}
|
||||
updateConfig={[MockFunction]}
|
||||
/>
|
||||
`;
|
||||
|
||||
|
@ -8,6 +8,7 @@ import type {RouteComponentProps} from 'react-router-dom';
|
||||
import type {CloudState} from '@mattermost/types/cloud';
|
||||
import type {AdminConfig, ClientLicense, EnvironmentConfig} from '@mattermost/types/config';
|
||||
import type {Role} from '@mattermost/types/roles';
|
||||
import type {DeepPartial} from '@mattermost/types/utilities';
|
||||
|
||||
import type {ActionResult} from 'mattermost-redux/types/actions';
|
||||
|
||||
@ -43,7 +44,7 @@ type ExtraProps = {
|
||||
setNavigationBlocked: (blocked: boolean) => void;
|
||||
roles: Record<string, Role>;
|
||||
editRole: (role: Role) => void;
|
||||
updateConfig: (config: AdminConfig) => Promise<ActionResult>;
|
||||
patchConfig: (config: DeepPartial<AdminConfig>) => Promise<ActionResult>;
|
||||
cloud: CloudState;
|
||||
isCurrentUserSystemAdmin: boolean;
|
||||
}
|
||||
@ -173,7 +174,7 @@ class AdminConsole extends React.PureComponent<Props, State> {
|
||||
showNavigationPrompt,
|
||||
roles,
|
||||
} = this.props;
|
||||
const {setNavigationBlocked, cancelNavigation, confirmNavigation, editRole, updateConfig} = this.props.actions;
|
||||
const {setNavigationBlocked, cancelNavigation, confirmNavigation, editRole, patchConfig} = this.props.actions;
|
||||
|
||||
if (!this.props.currentUserHasAnAdminRole) {
|
||||
return (
|
||||
@ -203,7 +204,7 @@ class AdminConsole extends React.PureComponent<Props, State> {
|
||||
setNavigationBlocked,
|
||||
roles,
|
||||
editRole,
|
||||
updateConfig,
|
||||
patchConfig,
|
||||
cloud: this.props.cloud,
|
||||
isCurrentUserSystemAdmin: this.props.isCurrentUserSystemAdmin,
|
||||
};
|
||||
|
@ -19,7 +19,7 @@ export type BaseProps = {
|
||||
environmentConfig?: EnvironmentConfig;
|
||||
setNavigationBlocked?: (blocked: boolean) => void;
|
||||
isDisabled?: boolean;
|
||||
updateConfig?: (config: AdminConfig) => {data: AdminConfig; error: ClientErrorPlaceholder};
|
||||
patchConfig?: (config: DeepPartial<AdminConfig>) => {data: AdminConfig; error: ClientErrorPlaceholder};
|
||||
}
|
||||
|
||||
export type BaseState = {
|
||||
@ -31,7 +31,7 @@ export type BaseState = {
|
||||
}
|
||||
|
||||
// Placeholder type until ClientError is exported from redux.
|
||||
// TODO: remove ClientErrorPlaceholder and change the return type of updateConfig
|
||||
// TODO: remove ClientErrorPlaceholder and change the return type of patchConfig
|
||||
type ClientErrorPlaceholder = {
|
||||
message: string;
|
||||
server_error_id: string;
|
||||
@ -107,8 +107,8 @@ export default abstract class AdminSettings <Props extends BaseProps, State exte
|
||||
let config = JSON.parse(JSON.stringify(this.props.config));
|
||||
config = this.getConfigFromState(config);
|
||||
|
||||
if (this.props.updateConfig) {
|
||||
const {data, error} = await this.props.updateConfig(config);
|
||||
if (this.props.patchConfig) {
|
||||
const {data, error} = await this.props.patchConfig(config);
|
||||
|
||||
if (data) {
|
||||
this.setState(this.getStateFromConfig(data) as State);
|
||||
|
@ -137,7 +137,7 @@ describe('components/admin_console/CustomPluginSettings', () => {
|
||||
{...baseProps}
|
||||
config={config}
|
||||
schema={{...plugin.settings_schema, id: plugin.id, name: plugin.name, settings}}
|
||||
updateConfig={jest.fn()}
|
||||
patchConfig={jest.fn()}
|
||||
/>,
|
||||
);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
@ -152,7 +152,7 @@ describe('components/admin_console/CustomPluginSettings', () => {
|
||||
id: 'testplugin',
|
||||
name: 'testplugin',
|
||||
}}
|
||||
updateConfig={jest.fn()}
|
||||
patchConfig={jest.fn()}
|
||||
/>,
|
||||
);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
@ -171,7 +171,7 @@ describe('components/admin_console/CustomPluginSettings', () => {
|
||||
} as PluginSettings,
|
||||
}}
|
||||
schema={{...plugin.settings_schema, id: plugin.id, name: plugin.name, settings}}
|
||||
updateConfig={jest.fn()}
|
||||
patchConfig={jest.fn()}
|
||||
/>,
|
||||
);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
|
@ -25,7 +25,7 @@ describe('components/admin_console/CustomTermsOfServiceSettings', () => {
|
||||
CustomTermsOfService: 'true',
|
||||
},
|
||||
setNavigationBlocked: jest.fn(),
|
||||
updateConfig: jest.fn(),
|
||||
patchConfig: jest.fn(),
|
||||
};
|
||||
|
||||
test('should match snapshot', () => {
|
||||
|
@ -31,7 +31,7 @@ type Props = BaseProps & {
|
||||
/*
|
||||
* Action to save config file
|
||||
*/
|
||||
updateConfig: () => void;
|
||||
patchConfig: () => void;
|
||||
};
|
||||
|
||||
type State = BaseState & {
|
||||
@ -120,7 +120,7 @@ export default class CustomTermsOfServiceSettings extends AdminSettings<Props, S
|
||||
let config = JSON.parse(JSON.stringify(this.props.config));
|
||||
config = this.getConfigFromState(config);
|
||||
|
||||
const {data, error} = await this.props.updateConfig(config);
|
||||
const {data, error} = await this.props.patchConfig(config);
|
||||
|
||||
if (data) {
|
||||
this.setState(this.getStateFromConfig(data));
|
||||
|
@ -29,7 +29,7 @@ describe('components/admin_console/data_retention_settings/data_retention_settin
|
||||
createJob: jest.fn(),
|
||||
getJobsByType: jest.fn().mockResolvedValue([]),
|
||||
deleteDataRetentionCustomPolicy: jest.fn(),
|
||||
updateConfig: jest.fn(),
|
||||
patchConfig: jest.fn(),
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -44,7 +44,7 @@ type Props = {
|
||||
createJob: (job: JobTypeBase) => Promise<ActionResult>;
|
||||
getJobsByType: (job: JobType) => Promise<ActionResult>;
|
||||
deleteDataRetentionCustomPolicy: (id: string) => Promise<ActionResult>;
|
||||
updateConfig: (config: AdminConfig) => Promise<ActionResult>;
|
||||
patchConfig: (config: DeepPartial<AdminConfig>) => Promise<ActionResult>;
|
||||
};
|
||||
} & WrappedComponentProps;
|
||||
|
||||
@ -437,7 +437,7 @@ class DataRetentionSettings extends React.PureComponent<Props, State> {
|
||||
const newConfig = JSON.parse(JSON.stringify(this.props.config));
|
||||
newConfig.DataRetentionSettings.DeletionJobStartTime = value;
|
||||
|
||||
await this.props.actions.updateConfig(newConfig);
|
||||
await this.props.actions.patchConfig(newConfig);
|
||||
this.inputRef.current?.blur();
|
||||
};
|
||||
|
||||
|
@ -21,7 +21,7 @@ describe('components/PluginManagement', () => {
|
||||
fileRetentionHours: '2400',
|
||||
environmentConfig: {},
|
||||
actions: {
|
||||
updateConfig: jest.fn(),
|
||||
patchConfig: jest.fn(),
|
||||
setNavigationBlocked: jest.fn(),
|
||||
},
|
||||
};
|
||||
|
@ -32,7 +32,7 @@ type Props = {
|
||||
fileRetentionHours: string | undefined;
|
||||
environmentConfig: Partial<EnvironmentConfig>;
|
||||
actions: {
|
||||
updateConfig: (config: AdminConfig) => Promise<ActionResult>;
|
||||
patchConfig: (config: DeepPartial<AdminConfig>) => Promise<ActionResult>;
|
||||
setNavigationBlocked: (blocked: boolean) => void;
|
||||
};
|
||||
};
|
||||
@ -121,7 +121,7 @@ export default class GlobalPolicyForm extends React.PureComponent<Props, State>
|
||||
newConfig.DataRetentionSettings.FileRetentionHours = this.setRetentionHours(fileRetentionDropdownValue.value, fileRetentionInputValue);
|
||||
}
|
||||
|
||||
const {error} = await this.props.actions.updateConfig(newConfig);
|
||||
const {error} = await this.props.actions.patchConfig(newConfig);
|
||||
|
||||
if (error) {
|
||||
this.setState({serverError: error.message, saving: false});
|
||||
|
@ -6,7 +6,7 @@ import {bindActionCreators} from 'redux';
|
||||
import type {Dispatch} from 'redux';
|
||||
|
||||
import {
|
||||
updateConfig,
|
||||
patchConfig,
|
||||
} from 'mattermost-redux/actions/admin';
|
||||
import {getEnvironmentConfig} from 'mattermost-redux/selectors/entities/admin';
|
||||
import {getConfig} from 'mattermost-redux/selectors/entities/general';
|
||||
@ -31,7 +31,7 @@ function mapStateToProps(state: GlobalState) {
|
||||
function mapDispatchToProps(dispatch: Dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators({
|
||||
updateConfig,
|
||||
patchConfig,
|
||||
setNavigationBlocked,
|
||||
}, dispatch),
|
||||
};
|
||||
|
@ -5,7 +5,7 @@ import {connect} from 'react-redux';
|
||||
import {bindActionCreators} from 'redux';
|
||||
import type {Dispatch} from 'redux';
|
||||
|
||||
import {getDataRetentionCustomPolicies as fetchDataRetentionCustomPolicies, deleteDataRetentionCustomPolicy, updateConfig} from 'mattermost-redux/actions/admin';
|
||||
import {getDataRetentionCustomPolicies as fetchDataRetentionCustomPolicies, deleteDataRetentionCustomPolicy, patchConfig} from 'mattermost-redux/actions/admin';
|
||||
import {createJob, getJobsByType} from 'mattermost-redux/actions/jobs';
|
||||
import {getDataRetentionCustomPolicies, getDataRetentionCustomPoliciesCount} from 'mattermost-redux/selectors/entities/admin';
|
||||
import {getConfig} from 'mattermost-redux/selectors/entities/general';
|
||||
@ -35,7 +35,7 @@ function mapDispatchToProps(dispatch: Dispatch) {
|
||||
createJob,
|
||||
getJobsByType,
|
||||
deleteDataRetentionCustomPolicy,
|
||||
updateConfig,
|
||||
patchConfig,
|
||||
}, dispatch),
|
||||
};
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ import type {ConnectedProps} from 'react-redux';
|
||||
import {bindActionCreators} from 'redux';
|
||||
import type {Dispatch} from 'redux';
|
||||
|
||||
import {getConfig, getEnvironmentConfig, updateConfig} from 'mattermost-redux/actions/admin';
|
||||
import {getConfig, getEnvironmentConfig, patchConfig} from 'mattermost-redux/actions/admin';
|
||||
import {loadRolesIfNeeded, editRole} from 'mattermost-redux/actions/roles';
|
||||
import {selectTeam} from 'mattermost-redux/actions/teams';
|
||||
import {General} from 'mattermost-redux/constants';
|
||||
@ -60,7 +60,7 @@ function mapDispatchToProps(dispatch: Dispatch) {
|
||||
actions: bindActionCreators({
|
||||
getConfig,
|
||||
getEnvironmentConfig,
|
||||
updateConfig,
|
||||
patchConfig,
|
||||
setNavigationBlocked,
|
||||
deferNavigation,
|
||||
cancelNavigation,
|
||||
|
@ -5,14 +5,14 @@ import {connect} from 'react-redux';
|
||||
import {bindActionCreators} from 'redux';
|
||||
import type {Dispatch} from 'redux';
|
||||
|
||||
import {updateConfig} from 'mattermost-redux/actions/admin';
|
||||
import {patchConfig} from 'mattermost-redux/actions/admin';
|
||||
|
||||
import OpenIdConvert from './openid_convert';
|
||||
|
||||
function mapDispatchToProps(dispatch: Dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators({
|
||||
updateConfig,
|
||||
patchConfig,
|
||||
}, dispatch),
|
||||
};
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ import OpenIdConvert from 'components/admin_console/openid_convert/openid_conver
|
||||
describe('components/OpenIdConvert', () => {
|
||||
const baseProps = {
|
||||
actions: {
|
||||
updateConfig: jest.fn(),
|
||||
patchConfig: jest.fn(),
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -5,6 +5,7 @@ import React from 'react';
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
|
||||
import type {AdminConfig} from '@mattermost/types/config';
|
||||
import type {DeepPartial} from '@mattermost/types/utilities';
|
||||
|
||||
import type {ActionResult} from 'mattermost-redux/types/actions';
|
||||
|
||||
@ -21,7 +22,7 @@ import './openid_convert.scss';
|
||||
type Props = BaseProps & {
|
||||
disabled?: boolean;
|
||||
actions: {
|
||||
updateConfig: (config: AdminConfig) => Promise<ActionResult>;
|
||||
patchConfig: (config: DeepPartial<AdminConfig>) => Promise<ActionResult>;
|
||||
};
|
||||
};
|
||||
type State = {
|
||||
@ -59,7 +60,7 @@ export default class OpenIdConvert extends React.PureComponent<Props, State> {
|
||||
newConfig[setting].TokenEndpoint = '';
|
||||
});
|
||||
|
||||
const {error: err} = await this.props.actions.updateConfig(newConfig);
|
||||
const {error: err} = await this.props.actions.patchConfig(newConfig);
|
||||
if (err) {
|
||||
this.setState({serverError: err.message});
|
||||
} else {
|
||||
|
@ -6,6 +6,7 @@ import {Modal} from 'react-bootstrap';
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
|
||||
import type {AdminConfig} from '@mattermost/types/config';
|
||||
import type {DeepPartial} from '@mattermost/types/utilities';
|
||||
|
||||
import type {ActionResult} from 'mattermost-redux/types/actions';
|
||||
|
||||
@ -22,7 +23,7 @@ type Props ={
|
||||
show: boolean;
|
||||
onClose: () => void;
|
||||
actions: {
|
||||
updateConfig: (config: AdminConfig) => Promise<ActionResult>;
|
||||
patchConfig: (config: DeepPartial<AdminConfig>) => Promise<ActionResult>;
|
||||
};
|
||||
}
|
||||
|
||||
@ -48,7 +49,7 @@ export default function EditPostTimeLimitModal(props: Props) {
|
||||
const newConfig = JSON.parse(JSON.stringify(props.config));
|
||||
newConfig.ServiceSettings.PostEditTimeLimit = alwaysAllowPostEditing ? Constants.UNSET_POST_EDIT_TIME_LIMIT : postEditTimeLimit;
|
||||
|
||||
const {error} = await props.actions.updateConfig(newConfig);
|
||||
const {error} = await props.actions.patchConfig(newConfig);
|
||||
if (error) {
|
||||
setErrorMessage(error.message);
|
||||
setSaving(false);
|
||||
|
@ -5,7 +5,7 @@ import {connect} from 'react-redux';
|
||||
import {bindActionCreators} from 'redux';
|
||||
import type {Dispatch} from 'redux';
|
||||
|
||||
import {updateConfig} from 'mattermost-redux/actions/admin';
|
||||
import {patchConfig} from 'mattermost-redux/actions/admin';
|
||||
import {getConfig} from 'mattermost-redux/selectors/entities/admin';
|
||||
|
||||
import type {GlobalState} from 'types/store';
|
||||
@ -20,7 +20,7 @@ function mapStateToProps(state: GlobalState) {
|
||||
|
||||
function mapDispatchToProps(dispatch: Dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators({updateConfig}, dispatch),
|
||||
actions: bindActionCreators({patchConfig}, dispatch),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -256,7 +256,7 @@ describe('components/admin_console/SchemaAdminSettings', () => {
|
||||
config={config}
|
||||
environmentConfig={environmentConfig}
|
||||
schema={{...schema} as AdminDefinitionSubSectionSchema}
|
||||
updateConfig={jest.fn()}
|
||||
patchConfig={jest.fn()}
|
||||
/>,
|
||||
);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
@ -269,7 +269,7 @@ describe('components/admin_console/SchemaAdminSettings', () => {
|
||||
config={config}
|
||||
environmentConfig={environmentConfig}
|
||||
schema={{component: () => <p>{'Test'}</p>} as AdminDefinitionSubSectionSchema}
|
||||
updateConfig={jest.fn()}
|
||||
patchConfig={jest.fn()}
|
||||
/>,
|
||||
);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
@ -285,7 +285,7 @@ describe('components/admin_console/SchemaAdminSettings', () => {
|
||||
...schema,
|
||||
header: headerText,
|
||||
} as AdminDefinitionSubSectionSchema,
|
||||
updateConfig: jest.fn(),
|
||||
patchConfig: jest.fn(),
|
||||
};
|
||||
|
||||
const wrapper = shallowWithIntl(<SchemaAdminSettings {...props}/>);
|
||||
@ -308,7 +308,7 @@ describe('components/admin_console/SchemaAdminSettings', () => {
|
||||
...schema,
|
||||
footer: footerText,
|
||||
} as AdminDefinitionSubSectionSchema,
|
||||
updateConfig: jest.fn(),
|
||||
patchConfig: jest.fn(),
|
||||
};
|
||||
|
||||
const wrapper = shallowWithIntl(<SchemaAdminSettings {...props}/>);
|
||||
@ -327,7 +327,7 @@ describe('components/admin_console/SchemaAdminSettings', () => {
|
||||
config,
|
||||
environmentConfig,
|
||||
schema: null,
|
||||
updateConfig: jest.fn(),
|
||||
patchConfig: jest.fn(),
|
||||
};
|
||||
|
||||
const wrapper = shallowWithIntl(<SchemaAdminSettings {...props}/>);
|
||||
@ -360,7 +360,7 @@ describe('components/admin_console/SchemaAdminSettings', () => {
|
||||
id: '',
|
||||
environmentConfig,
|
||||
schema: localSchema,
|
||||
updateConfig: jest.fn(),
|
||||
patchConfig: jest.fn(),
|
||||
};
|
||||
|
||||
const wrapper = shallowWithIntl(<SchemaAdminSettings {...props}/>);
|
||||
@ -389,7 +389,7 @@ describe('components/admin_console/SchemaAdminSettings', () => {
|
||||
config,
|
||||
environmentConfig,
|
||||
schema: localSchema,
|
||||
updateConfig: jest.fn(),
|
||||
patchConfig: jest.fn(),
|
||||
};
|
||||
|
||||
const wrapper = shallowWithIntl(<SchemaAdminSettings {...props}/>);
|
||||
|
@ -10,6 +10,7 @@ import {Link} from 'react-router-dom';
|
||||
import type {CloudState} from '@mattermost/types/cloud';
|
||||
import type {AdminConfig, ClientLicense, EnvironmentConfig} from '@mattermost/types/config';
|
||||
import type {Role} from '@mattermost/types/roles';
|
||||
import type {DeepPartial} from '@mattermost/types/utilities';
|
||||
|
||||
import type {ActionResult} from 'mattermost-redux/types/actions';
|
||||
|
||||
@ -53,7 +54,7 @@ type Props = {
|
||||
roles: Record<string, Role>;
|
||||
license: ClientLicense;
|
||||
editRole: (role: Role) => void;
|
||||
updateConfig: (config: AdminConfig) => Promise<ActionResult>;
|
||||
patchConfig: (config: DeepPartial<AdminConfig>) => Promise<ActionResult>;
|
||||
isDisabled: boolean;
|
||||
consoleAccess: ConsoleAccess;
|
||||
cloud: CloudState;
|
||||
@ -1145,7 +1146,7 @@ export class SchemaAdminSettings extends React.PureComponent<Props, State> {
|
||||
let config = JSON.parse(JSON.stringify(this.props.config));
|
||||
config = this.getConfigFromState(config);
|
||||
|
||||
const {error} = await this.props.updateConfig(config);
|
||||
const {error} = await this.props.patchConfig(config);
|
||||
if (error) {
|
||||
this.setState({
|
||||
serverError: error.message,
|
||||
|
@ -292,7 +292,7 @@ callbackUrl2.com
|
||||
values={
|
||||
Object {
|
||||
"link": <ExternalLink
|
||||
href="https://mattermost.com/pl/configure-session-lengths"
|
||||
href="https://mattermost.com/pl/default-allow-untrusted-internal-connections"
|
||||
location="abstract_outgoing_webhook"
|
||||
>
|
||||
<Memo(MemoizedFormattedMessage)
|
||||
|
@ -504,7 +504,7 @@ export default class AbstractOutgoingWebhook extends React.PureComponent<Props,
|
||||
values={{
|
||||
link: (
|
||||
<ExternalLink
|
||||
href={DocLinks.SESSION_LENGTHS}
|
||||
href={DocLinks.TRUSTED_CONNECTION}
|
||||
location='abstract_outgoing_webhook'
|
||||
>
|
||||
<FormattedMessage
|
||||
|
@ -13,7 +13,6 @@ describe('components/post_view/new_message_separator', () => {
|
||||
<NewMessageSeparator
|
||||
separatorId='1234'
|
||||
newMessagesSeparatorActions={[]}
|
||||
lastViewedAt={0}
|
||||
/>,
|
||||
);
|
||||
|
||||
|
@ -4,6 +4,8 @@
|
||||
import React, {memo} from 'react';
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
|
||||
import * as PostList from 'mattermost-redux/utils/post_list';
|
||||
|
||||
import NotificationSeparator from 'components/widgets/separator/notification-separator';
|
||||
|
||||
import type {PluginComponent} from 'types/store/plugins';
|
||||
@ -12,19 +14,19 @@ type Props = {
|
||||
separatorId: string;
|
||||
wrapperRef?: React.RefObject<HTMLDivElement>;
|
||||
newMessagesSeparatorActions: PluginComponent[];
|
||||
lastViewedAt: number;
|
||||
channelId?: string;
|
||||
threadId?: string;
|
||||
}
|
||||
|
||||
const NewMessageSeparator = ({
|
||||
newMessagesSeparatorActions,
|
||||
lastViewedAt,
|
||||
channelId,
|
||||
threadId,
|
||||
wrapperRef,
|
||||
separatorId,
|
||||
}: Props) => {
|
||||
const lastViewedAt = PostList.getTimestampForStartOfNewMessages(separatorId);
|
||||
|
||||
const pluginItems = newMessagesSeparatorActions?.
|
||||
map((item) => {
|
||||
if (!item.component) {
|
||||
@ -47,7 +49,7 @@ const NewMessageSeparator = ({
|
||||
ref={wrapperRef}
|
||||
className='new-separator'
|
||||
>
|
||||
<NotificationSeparator id={separatorId}>
|
||||
<NotificationSeparator>
|
||||
<FormattedMessage
|
||||
id='posts_view.newMsg'
|
||||
defaultMessage='New Messages'
|
||||
|
@ -95,9 +95,8 @@ exports[`components/post_view/post_list_row should render more messages loading
|
||||
exports[`components/post_view/post_list_row should render new messages line 1`] = `
|
||||
<Memo(NewMessageSeparator)
|
||||
channelId="channel_id_1"
|
||||
lastViewedAt={0}
|
||||
newMessagesSeparatorActions={Array []}
|
||||
separatorId="start-of-new-messages"
|
||||
separatorId="start-of-new-messages-1553106600000"
|
||||
/>
|
||||
`;
|
||||
|
||||
|
@ -41,7 +41,6 @@ describe('components/post_view/post_list_row', () => {
|
||||
post: TestHelper.getPostMock({id: 'post_id_1'}),
|
||||
currentUserId: 'user_id_1',
|
||||
newMessagesSeparatorActions: [],
|
||||
lastViewedAt: 0,
|
||||
channelId: 'channel_id_1',
|
||||
};
|
||||
|
||||
@ -107,7 +106,7 @@ describe('components/post_view/post_list_row', () => {
|
||||
});
|
||||
|
||||
test('should render new messages line', () => {
|
||||
const listId = PostListRowListIds.START_OF_NEW_MESSAGES;
|
||||
const listId = PostListRowListIds.START_OF_NEW_MESSAGES + '1553106600000';
|
||||
const props = {
|
||||
...defaultProps,
|
||||
listId,
|
||||
|
@ -57,7 +57,6 @@ export type PostListRowProps = {
|
||||
limitsLoaded: boolean;
|
||||
exceededLimitChannelId?: string;
|
||||
firstInaccessiblePostTime?: number;
|
||||
lastViewedAt: number;
|
||||
channelId: string;
|
||||
|
||||
newMessagesSeparatorActions: PluginComponent[];
|
||||
@ -120,7 +119,6 @@ export default class PostListRow extends React.PureComponent<PostListRowProps> {
|
||||
separatorId={listId}
|
||||
newMessagesSeparatorActions={this.props.newMessagesSeparatorActions}
|
||||
channelId={this.props.channelId}
|
||||
lastViewedAt={this.props.lastViewedAt}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ describe('PostList', () => {
|
||||
'post3',
|
||||
DATE_LINE + 1551711600000,
|
||||
'post4',
|
||||
PostListRowListIds.START_OF_NEW_MESSAGES,
|
||||
PostListRowListIds.START_OF_NEW_MESSAGES + 1551711601000,
|
||||
'post5',
|
||||
];
|
||||
|
||||
@ -459,7 +459,7 @@ describe('PostList', () => {
|
||||
for (let i = 0; i < 120; i++) {
|
||||
postListIds.push(`post${i}`);
|
||||
}
|
||||
postListIds[65] = PostListRowListIds.START_OF_NEW_MESSAGES;
|
||||
postListIds[65] = PostListRowListIds.START_OF_NEW_MESSAGES + 1551711601000;
|
||||
|
||||
const props = {
|
||||
...baseProps,
|
||||
@ -506,7 +506,7 @@ describe('PostList', () => {
|
||||
'post3',
|
||||
DATE_LINE + 1551711600000,
|
||||
'post4',
|
||||
PostListRowListIds.START_OF_NEW_MESSAGES,
|
||||
PostListRowListIds.START_OF_NEW_MESSAGES + 1551711601000,
|
||||
'post5',
|
||||
],
|
||||
};
|
||||
@ -531,7 +531,7 @@ describe('PostList', () => {
|
||||
'post3',
|
||||
DATE_LINE + 1551711600000,
|
||||
'post4',
|
||||
PostListRowListIds.START_OF_NEW_MESSAGES,
|
||||
PostListRowListIds.START_OF_NEW_MESSAGES + 1551711601000,
|
||||
'post5',
|
||||
],
|
||||
};
|
||||
@ -614,7 +614,7 @@ describe('PostList', () => {
|
||||
'post2',
|
||||
'post3',
|
||||
'post4',
|
||||
PostListRowListIds.START_OF_NEW_MESSAGES,
|
||||
PostListRowListIds.START_OF_NEW_MESSAGES + 1551711599000,
|
||||
DATE_LINE + 1551711600000,
|
||||
'post5',
|
||||
];
|
||||
@ -637,7 +637,7 @@ describe('PostList', () => {
|
||||
'post2',
|
||||
'post3',
|
||||
'post4',
|
||||
PostListRowListIds.START_OF_NEW_MESSAGES,
|
||||
PostListRowListIds.START_OF_NEW_MESSAGES + 1551711601000,
|
||||
'post5',
|
||||
];
|
||||
|
||||
|
@ -9,7 +9,7 @@ import React from 'react';
|
||||
import AutoSizer from 'react-virtualized-auto-sizer';
|
||||
|
||||
import EventEmitter from 'mattermost-redux/utils/event_emitter';
|
||||
import {isDateLine, isStartOfNewMessages} from 'mattermost-redux/utils/post_list';
|
||||
import {getNewMessagesIndex, isDateLine, isStartOfNewMessages} from 'mattermost-redux/utils/post_list';
|
||||
|
||||
import type {updateNewMessagesAtInChannel} from 'actions/global_actions';
|
||||
import type {CanLoadMorePosts} from 'actions/views/channel';
|
||||
@ -22,7 +22,7 @@ import ToastWrapper from 'components/toast_wrapper';
|
||||
import Pluggable from 'plugins/pluggable';
|
||||
import Constants, {PostListRowListIds, EventTypes, PostRequestTypes} from 'utils/constants';
|
||||
import DelayedAction from 'utils/delayed_action';
|
||||
import {getPreviousPostId, getLatestPostId, getNewMessageIndex} from 'utils/post_utils';
|
||||
import {getPreviousPostId, getLatestPostId} from 'utils/post_utils';
|
||||
import * as Utils from 'utils/utils';
|
||||
|
||||
import LatestPostReader from './latest_post_reader';
|
||||
@ -193,9 +193,9 @@ export default class PostList extends React.PureComponent<Props, State> {
|
||||
if (props.focusedPostId) {
|
||||
postIndex = (this.props.postListIds || []).findIndex((postId) => postId === this.props.focusedPostId);
|
||||
} else {
|
||||
postIndex = this.getNewMessagesSeparatorIndex(props.postListIds || []);
|
||||
postIndex = getNewMessagesIndex(props.postListIds || []);
|
||||
}
|
||||
this.newMessageLineIndex = this.getNewMessagesSeparatorIndex(props.postListIds || []);
|
||||
this.newMessageLineIndex = getNewMessagesIndex(props.postListIds || []);
|
||||
|
||||
const maxPostsForSlicing = props.focusedPostId ? MAXIMUM_POSTS_FOR_SLICING.permalink : MAXIMUM_POSTS_FOR_SLICING.channel;
|
||||
this.initRangeToRender = [
|
||||
@ -241,7 +241,7 @@ export default class PostList extends React.PureComponent<Props, State> {
|
||||
const prevPostsCount = (prevProps.postListIds || []).length;
|
||||
const presentPostsCount = (this.props.postListIds || []).length;
|
||||
|
||||
this.newMessageLineIndex = this.getNewMessagesSeparatorIndex(this.props.postListIds || []);
|
||||
this.newMessageLineIndex = getNewMessagesIndex(this.props.postListIds || []);
|
||||
|
||||
if (snapshot) {
|
||||
const postlistScrollHeight = this.postListRef.current.scrollHeight;
|
||||
@ -309,12 +309,6 @@ export default class PostList extends React.PureComponent<Props, State> {
|
||||
return nextState;
|
||||
}
|
||||
|
||||
getNewMessagesSeparatorIndex = (postListIds: string[]) => {
|
||||
return postListIds.findIndex(
|
||||
(item) => item.indexOf(PostListRowListIds.START_OF_NEW_MESSAGES) === 0,
|
||||
);
|
||||
};
|
||||
|
||||
handleWindowResize = () => {
|
||||
this.showSearchHintThreshold = this.getShowSearchHintThreshold();
|
||||
};
|
||||
@ -377,7 +371,6 @@ export default class PostList extends React.PureComponent<Props, State> {
|
||||
isLastPost={isLastPost}
|
||||
loadingNewerPosts={this.props.loadingNewerPosts}
|
||||
loadingOlderPosts={this.props.loadingOlderPosts}
|
||||
lastViewedAt={this.props.lastViewedAt}
|
||||
channelId={this.props.channelId}
|
||||
/>
|
||||
</div>
|
||||
@ -599,7 +592,7 @@ export default class PostList extends React.PureComponent<Props, State> {
|
||||
};
|
||||
}
|
||||
|
||||
const newMessagesSeparatorIndex = getNewMessageIndex(this.state.postListIds);
|
||||
const newMessagesSeparatorIndex = getNewMessagesIndex(this.state.postListIds);
|
||||
|
||||
if (newMessagesSeparatorIndex > 0) {
|
||||
// if there is a dateLine above START_OF_NEW_MESSAGES then scroll to date line
|
||||
@ -641,7 +634,7 @@ export default class PostList extends React.PureComponent<Props, State> {
|
||||
};
|
||||
|
||||
scrollToNewMessage = () => {
|
||||
this.listRef.current?.scrollToItem(getNewMessageIndex(this.state.postListIds), 'start', OFFSET_TO_SHOW_TOAST);
|
||||
this.listRef.current?.scrollToItem(getNewMessagesIndex(this.state.postListIds), 'start', OFFSET_TO_SHOW_TOAST);
|
||||
};
|
||||
|
||||
updateNewMessagesAtInChannel = (lastViewedAt = Date.now()) => {
|
||||
|
@ -60,6 +60,7 @@ function ThreadFooter({
|
||||
channel_id: channelId,
|
||||
},
|
||||
} = thread;
|
||||
|
||||
const participantIds = useMemo(() => (participants || []).map(({id}) => id).reverse(), [participants]);
|
||||
|
||||
const handleReply = useCallback((e) => {
|
||||
|
@ -32,6 +32,7 @@ describe('components/threading/ThreadViewer', () => {
|
||||
user_id: post.user_id,
|
||||
channel_id: post.channel_id,
|
||||
message: post.message,
|
||||
reply_count: 3,
|
||||
};
|
||||
|
||||
const channel: Channel = TestHelper.getChannelMock({
|
||||
|
@ -54,7 +54,6 @@ function makeMapStateToProps() {
|
||||
isMobileView: getIsMobileView(state),
|
||||
lastPost,
|
||||
replyListIds,
|
||||
lastViewedAt,
|
||||
newMessagesSeparatorActions,
|
||||
};
|
||||
};
|
||||
|
@ -22,13 +22,13 @@ import Reply from './reply';
|
||||
type Props = {
|
||||
a11yIndex: number;
|
||||
currentUserId: string;
|
||||
replyCount: number;
|
||||
isRootPost: boolean;
|
||||
isLastPost: boolean;
|
||||
listId: string;
|
||||
onCardClick: (post: Post) => void;
|
||||
previousPostId: string;
|
||||
timestampProps?: Partial<TimestampProps>;
|
||||
lastViewedAt: number;
|
||||
threadId: string;
|
||||
newMessagesSeparatorActions: PluginComponent[];
|
||||
};
|
||||
@ -40,10 +40,10 @@ function ThreadViewerRow({
|
||||
isRootPost,
|
||||
isLastPost,
|
||||
listId,
|
||||
replyCount,
|
||||
onCardClick,
|
||||
previousPostId,
|
||||
timestampProps,
|
||||
lastViewedAt,
|
||||
threadId,
|
||||
newMessagesSeparatorActions,
|
||||
}: Props) {
|
||||
@ -62,7 +62,6 @@ function ThreadViewerRow({
|
||||
return (
|
||||
<NewMessageSeparator
|
||||
separatorId={listId}
|
||||
lastViewedAt={lastViewedAt}
|
||||
threadId={threadId}
|
||||
newMessagesSeparatorActions={newMessagesSeparatorActions}
|
||||
/>
|
||||
@ -70,13 +69,20 @@ function ThreadViewerRow({
|
||||
|
||||
case isRootPost:
|
||||
return (
|
||||
<PostComponent
|
||||
postId={listId}
|
||||
isLastPost={isLastPost}
|
||||
handleCardClick={onCardClick}
|
||||
timestampProps={timestampProps}
|
||||
location={Locations.RHS_ROOT}
|
||||
/>
|
||||
<>
|
||||
<PostComponent
|
||||
postId={listId}
|
||||
isLastPost={isLastPost}
|
||||
handleCardClick={onCardClick}
|
||||
timestampProps={timestampProps}
|
||||
location={Locations.RHS_ROOT}
|
||||
/>
|
||||
{replyCount > 0 && (
|
||||
<div className='root-post__divider'>
|
||||
<div>{`${replyCount} Replies`}</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
case PostListUtils.isCombinedUserActivityPost(listId): {
|
||||
return (
|
||||
|
@ -26,6 +26,7 @@ function getBasePropsAndState(): [Props, DeepPartial<GlobalState>] {
|
||||
const currentUser = TestHelper.getUserMock({roles: 'role'});
|
||||
const post = TestHelper.getPostMock({
|
||||
channel_id: channel.id,
|
||||
reply_count: 0,
|
||||
});
|
||||
|
||||
const directTeammate: UserProfile = TestHelper.getUserMock();
|
||||
@ -40,7 +41,6 @@ function getBasePropsAndState(): [Props, DeepPartial<GlobalState>] {
|
||||
useRelativeTimestamp: true,
|
||||
isMobileView: false,
|
||||
isThreadView: false,
|
||||
lastViewedAt: 0,
|
||||
newMessagesSeparatorActions: [],
|
||||
fromSuppressed: false,
|
||||
};
|
||||
|
@ -3,15 +3,18 @@
|
||||
|
||||
import {DynamicSizeList} from 'dynamic-virtualized-list';
|
||||
import type {OnScrollArgs, OnItemsRenderedArgs} from 'dynamic-virtualized-list';
|
||||
import React, {PureComponent} from 'react';
|
||||
import React, {PureComponent, useMemo} from 'react';
|
||||
import type {RefObject} from 'react';
|
||||
import {useSelector} from 'react-redux';
|
||||
import AutoSizer from 'react-virtualized-auto-sizer';
|
||||
|
||||
import type {Channel} from '@mattermost/types/channels';
|
||||
import type {Post} from '@mattermost/types/posts';
|
||||
import type {UserProfile} from '@mattermost/types/users';
|
||||
|
||||
import {isDateLine, isStartOfNewMessages, isCreateComment} from 'mattermost-redux/utils/post_list';
|
||||
import {getPost} from 'mattermost-redux/selectors/entities/posts';
|
||||
import {makeGetThreadOrSynthetic} from 'mattermost-redux/selectors/entities/threads';
|
||||
import {getNewMessagesIndex, isDateLine, isStartOfNewMessages, isCreateComment} from 'mattermost-redux/utils/post_list';
|
||||
|
||||
import NewRepliesBanner from 'components/new_replies_banner';
|
||||
import FloatingTimestamp from 'components/post_view/floating_timestamp';
|
||||
@ -19,9 +22,10 @@ import {THREADING_TIME as BASE_THREADING_TIME} from 'components/threading/common
|
||||
|
||||
import Constants from 'utils/constants';
|
||||
import DelayedAction from 'utils/delayed_action';
|
||||
import {getNewMessageIndex, getPreviousPostId, getLatestPostId} from 'utils/post_utils';
|
||||
import {getPreviousPostId, getLatestPostId} from 'utils/post_utils';
|
||||
import * as Utils from 'utils/utils';
|
||||
|
||||
import type {GlobalState} from 'types/store';
|
||||
import type {PluginComponent} from 'types/store/plugins';
|
||||
import type {FakePost} from 'types/store/rhs';
|
||||
|
||||
@ -41,7 +45,6 @@ type Props = {
|
||||
useRelativeTimestamp: boolean;
|
||||
isMobileView: boolean;
|
||||
isThreadView: boolean;
|
||||
lastViewedAt: number;
|
||||
newMessagesSeparatorActions: PluginComponent[];
|
||||
inputPlaceholder?: string;
|
||||
fromSuppressed?: boolean;
|
||||
@ -168,7 +171,7 @@ class ThreadViewerVirtualized extends PureComponent<Props, State> {
|
||||
};
|
||||
}
|
||||
|
||||
const newMessagesSeparatorIndex = getNewMessageIndex(replyListIds);
|
||||
const newMessagesSeparatorIndex = getNewMessagesIndex(replyListIds);
|
||||
if (newMessagesSeparatorIndex > 0) {
|
||||
return {
|
||||
index: newMessagesSeparatorIndex,
|
||||
@ -250,7 +253,7 @@ class ThreadViewerVirtualized extends PureComponent<Props, State> {
|
||||
if (this.props.highlightedPostId) {
|
||||
postIndex = this.props.replyListIds.findIndex((postId) => postId === this.props.highlightedPostId);
|
||||
} else {
|
||||
postIndex = getNewMessageIndex(this.props.replyListIds);
|
||||
postIndex = getNewMessagesIndex(this.props.replyListIds);
|
||||
}
|
||||
|
||||
return postIndex === -1 ? 0 : postIndex;
|
||||
@ -303,7 +306,7 @@ class ThreadViewerVirtualized extends PureComponent<Props, State> {
|
||||
};
|
||||
|
||||
handleToastClick = () => {
|
||||
const index = getNewMessageIndex(this.props.replyListIds);
|
||||
const index = getNewMessagesIndex(this.props.replyListIds);
|
||||
if (index >= 0) {
|
||||
this.scrollToItem(index, 'start', OFFSET_TO_SHOW_TOAST);
|
||||
} else {
|
||||
@ -350,6 +353,14 @@ class ThreadViewerVirtualized extends PureComponent<Props, State> {
|
||||
const isLastPost = itemId === this.props.lastPost.id;
|
||||
const isRootPost = itemId === this.props.selected.id;
|
||||
|
||||
const post = useSelector((state: GlobalState) => getPost(state, this.props.selected.id));
|
||||
const getThreadOrSynthetic = useMemo(makeGetThreadOrSynthetic, []);
|
||||
|
||||
const totalReplies = useSelector((state: GlobalState) => {
|
||||
const thread = getThreadOrSynthetic(state, post);
|
||||
return thread.reply_count || 0;
|
||||
});
|
||||
|
||||
if (!isDateLine(itemId) && !isStartOfNewMessages(itemId) && !isCreateComment(itemId) && !isRootPost) {
|
||||
a11yIndex++;
|
||||
}
|
||||
@ -379,10 +390,10 @@ class ThreadViewerVirtualized extends PureComponent<Props, State> {
|
||||
isRootPost={isRootPost}
|
||||
isLastPost={isLastPost}
|
||||
listId={itemId}
|
||||
replyCount={totalReplies}
|
||||
onCardClick={this.props.onCardClick}
|
||||
previousPostId={getPreviousPostId(data, index)}
|
||||
timestampProps={this.props.useRelativeTimestamp ? THREADING_TIME : undefined}
|
||||
lastViewedAt={this.props.lastViewedAt}
|
||||
threadId={this.props.selected.id}
|
||||
newMessagesSeparatorActions={this.props.newMessagesSeparatorActions}
|
||||
/>
|
||||
@ -400,7 +411,7 @@ class ThreadViewerVirtualized extends PureComponent<Props, State> {
|
||||
|
||||
isNewMessagesVisible = (): boolean => {
|
||||
const {visibleStopIndex} = this.state;
|
||||
const newMessagesSeparatorIndex = getNewMessageIndex(this.props.replyListIds);
|
||||
const newMessagesSeparatorIndex = getNewMessagesIndex(this.props.replyListIds);
|
||||
if (visibleStopIndex != null) {
|
||||
return visibleStopIndex < newMessagesSeparatorIndex;
|
||||
}
|
||||
|
@ -85,7 +85,7 @@ describe('components/ToastWrapper', () => {
|
||||
'post1',
|
||||
'post2',
|
||||
'post3',
|
||||
PostListRowListIds.START_OF_NEW_MESSAGES,
|
||||
PostListRowListIds.START_OF_NEW_MESSAGES + 1551711599000,
|
||||
DATE_LINE + 1551711600000,
|
||||
'post4',
|
||||
'post5',
|
||||
@ -104,7 +104,7 @@ describe('components/ToastWrapper', () => {
|
||||
'post1',
|
||||
'post2',
|
||||
'post3',
|
||||
PostListRowListIds.START_OF_NEW_MESSAGES,
|
||||
PostListRowListIds.START_OF_NEW_MESSAGES + 1551711599000,
|
||||
DATE_LINE + 1551711600000,
|
||||
'post4',
|
||||
'post5',
|
||||
@ -162,7 +162,7 @@ describe('components/ToastWrapper', () => {
|
||||
'post1',
|
||||
'post2',
|
||||
'post3',
|
||||
PostListRowListIds.START_OF_NEW_MESSAGES,
|
||||
PostListRowListIds.START_OF_NEW_MESSAGES + 1551711599000,
|
||||
DATE_LINE + 1551711600000,
|
||||
'post4',
|
||||
'post5',
|
||||
@ -191,7 +191,7 @@ describe('components/ToastWrapper', () => {
|
||||
'post1',
|
||||
'post2',
|
||||
'post3',
|
||||
PostListRowListIds.START_OF_NEW_MESSAGES,
|
||||
PostListRowListIds.START_OF_NEW_MESSAGES + 1551711599000,
|
||||
DATE_LINE + 1551711600000,
|
||||
'post4',
|
||||
'post5',
|
||||
@ -247,7 +247,7 @@ describe('components/ToastWrapper', () => {
|
||||
'post1',
|
||||
'post2',
|
||||
'post3',
|
||||
PostListRowListIds.START_OF_NEW_MESSAGES,
|
||||
PostListRowListIds.START_OF_NEW_MESSAGES + 1551711599000,
|
||||
DATE_LINE + 1551711600000,
|
||||
'post4',
|
||||
'post5',
|
||||
@ -277,7 +277,7 @@ describe('components/ToastWrapper', () => {
|
||||
'post1',
|
||||
'post2',
|
||||
'post3',
|
||||
PostListRowListIds.START_OF_NEW_MESSAGES,
|
||||
PostListRowListIds.START_OF_NEW_MESSAGES + 1551711599000,
|
||||
DATE_LINE + 1551711600000,
|
||||
'post4',
|
||||
'post5',
|
||||
@ -312,7 +312,7 @@ describe('components/ToastWrapper', () => {
|
||||
'post1',
|
||||
'post2',
|
||||
'post3',
|
||||
PostListRowListIds.START_OF_NEW_MESSAGES,
|
||||
PostListRowListIds.START_OF_NEW_MESSAGES + 1551711599000,
|
||||
DATE_LINE + 1551711600000,
|
||||
'post4',
|
||||
'post5',
|
||||
@ -334,7 +334,7 @@ describe('components/ToastWrapper', () => {
|
||||
'post1',
|
||||
'post2',
|
||||
'post3',
|
||||
PostListRowListIds.START_OF_NEW_MESSAGES,
|
||||
PostListRowListIds.START_OF_NEW_MESSAGES + 1551711599000,
|
||||
DATE_LINE + 1551711600000,
|
||||
'post4',
|
||||
'post5',
|
||||
@ -356,7 +356,7 @@ describe('components/ToastWrapper', () => {
|
||||
'post1',
|
||||
'post2',
|
||||
'post3',
|
||||
PostListRowListIds.START_OF_NEW_MESSAGES,
|
||||
PostListRowListIds.START_OF_NEW_MESSAGES + 1551711599000,
|
||||
DATE_LINE + 1551711600000,
|
||||
'post4',
|
||||
'post5',
|
||||
@ -381,7 +381,7 @@ describe('components/ToastWrapper', () => {
|
||||
'post1',
|
||||
'post2',
|
||||
'post3',
|
||||
PostListRowListIds.START_OF_NEW_MESSAGES,
|
||||
PostListRowListIds.START_OF_NEW_MESSAGES + 1551711599000,
|
||||
DATE_LINE + 1551711600000,
|
||||
'post4',
|
||||
'post5',
|
||||
@ -403,7 +403,7 @@ describe('components/ToastWrapper', () => {
|
||||
'post1',
|
||||
'post2',
|
||||
'post3',
|
||||
PostListRowListIds.START_OF_NEW_MESSAGES,
|
||||
PostListRowListIds.START_OF_NEW_MESSAGES + 1551711599000,
|
||||
DATE_LINE + 1551711600000,
|
||||
'post4',
|
||||
'post5',
|
||||
@ -426,7 +426,7 @@ describe('components/ToastWrapper', () => {
|
||||
'post1',
|
||||
'post2',
|
||||
'post3',
|
||||
PostListRowListIds.START_OF_NEW_MESSAGES,
|
||||
PostListRowListIds.START_OF_NEW_MESSAGES + 1551711599000,
|
||||
DATE_LINE + 1551711600000,
|
||||
'post4',
|
||||
'post5',
|
||||
@ -464,7 +464,7 @@ describe('components/ToastWrapper', () => {
|
||||
postListIds: [
|
||||
'post2',
|
||||
'post3',
|
||||
PostListRowListIds.START_OF_NEW_MESSAGES,
|
||||
PostListRowListIds.START_OF_NEW_MESSAGES + 1551711599000,
|
||||
DATE_LINE + 1551711600000,
|
||||
'post4',
|
||||
'post5',
|
||||
@ -480,7 +480,7 @@ describe('components/ToastWrapper', () => {
|
||||
'post1',
|
||||
'post2',
|
||||
'post3',
|
||||
PostListRowListIds.START_OF_NEW_MESSAGES,
|
||||
PostListRowListIds.START_OF_NEW_MESSAGES + 1551711599000,
|
||||
DATE_LINE + 1551711600000,
|
||||
'post4',
|
||||
'post5',
|
||||
@ -497,7 +497,7 @@ describe('components/ToastWrapper', () => {
|
||||
'post1',
|
||||
'post2',
|
||||
'post3',
|
||||
PostListRowListIds.START_OF_NEW_MESSAGES,
|
||||
PostListRowListIds.START_OF_NEW_MESSAGES + 1551711599000,
|
||||
DATE_LINE + 1551711600000,
|
||||
'post4',
|
||||
'post5',
|
||||
|
@ -7,6 +7,7 @@ import type {IntlShape, WrappedComponentProps} from 'react-intl';
|
||||
import type {RouteComponentProps} from 'react-router-dom';
|
||||
|
||||
import {Preferences} from 'mattermost-redux/constants';
|
||||
import {getNewMessagesIndex} from 'mattermost-redux/utils/post_list';
|
||||
|
||||
import {HintToast} from 'components/hint-toast/hint_toast';
|
||||
import ScrollToBottomToast from 'components/scroll_to_bottom_toast';
|
||||
@ -18,7 +19,7 @@ import {getHistory} from 'utils/browser_history';
|
||||
import Constants from 'utils/constants';
|
||||
import {isToday} from 'utils/datetime';
|
||||
import {isKeyPressed} from 'utils/keyboard';
|
||||
import {isIdNotPost, getNewMessageIndex} from 'utils/post_utils';
|
||||
import {isIdNotPost} from 'utils/post_utils';
|
||||
import {localizeMessage} from 'utils/utils';
|
||||
|
||||
import './toast__wrapper.scss';
|
||||
@ -91,7 +92,7 @@ export class ToastWrapperClass extends React.PureComponent<Props, State> {
|
||||
}
|
||||
|
||||
static countNewMessages = (rootPosts: Record<string, boolean>, isCollapsedThreadsEnabled: boolean, postListIds: string[] = []) => {
|
||||
const mark = getNewMessageIndex(postListIds);
|
||||
const mark = getNewMessagesIndex(postListIds);
|
||||
if (mark <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -5,7 +5,9 @@ import React from 'react';
|
||||
import './separator.scss';
|
||||
import './notification-separator.scss';
|
||||
|
||||
type Props = React.PropsWithChildren<any>;
|
||||
type Props = {
|
||||
children?: React.ReactNode;
|
||||
};
|
||||
|
||||
const NotificationSeparator = ({children}: Props) => {
|
||||
return (
|
||||
|
@ -112,26 +112,35 @@ describe('Actions.Admin', () => {
|
||||
expect(config.TeamSettings.SiteName === 'Mattermost').toBeTruthy();
|
||||
});
|
||||
|
||||
it('updateConfig', async () => {
|
||||
it('patchConfig', async () => {
|
||||
nock(Client4.getBaseRoute()).
|
||||
get('/config').
|
||||
reply(200, {
|
||||
TeamSettings: {
|
||||
SiteName: 'Mattermost',
|
||||
TeammateNameDisplay: 'username',
|
||||
},
|
||||
});
|
||||
|
||||
const {data} = await store.dispatch(Actions.getConfig());
|
||||
const updated = JSON.parse(JSON.stringify(data));
|
||||
|
||||
// Creating a copy.
|
||||
const reply = JSON.parse(JSON.stringify(data));
|
||||
const oldSiteName = updated.TeamSettings.SiteName;
|
||||
const oldNameDisplay = updated.TeamSettings.TeammateNameDisplay;
|
||||
const testSiteName = 'MattermostReduxTest';
|
||||
updated.TeamSettings.SiteName = testSiteName;
|
||||
reply.TeamSettings.SiteName = testSiteName;
|
||||
|
||||
// Testing partial config patch.
|
||||
updated.TeamSettings.TeammateNameDisplay = null;
|
||||
|
||||
nock(Client4.getBaseRoute()).
|
||||
put('/config').
|
||||
reply(200, updated);
|
||||
put('/config/patch').
|
||||
reply(200, reply);
|
||||
|
||||
await store.dispatch(Actions.updateConfig(updated));
|
||||
await store.dispatch(Actions.patchConfig(updated));
|
||||
|
||||
let state = store.getState();
|
||||
|
||||
@ -139,14 +148,15 @@ describe('Actions.Admin', () => {
|
||||
expect(config).toBeTruthy();
|
||||
expect(config.TeamSettings).toBeTruthy();
|
||||
expect(config.TeamSettings.SiteName === testSiteName).toBeTruthy();
|
||||
expect(config.TeamSettings.TeammateNameDisplay === oldNameDisplay).toBeTruthy();
|
||||
|
||||
updated.TeamSettings.SiteName = oldSiteName;
|
||||
|
||||
nock(Client4.getBaseRoute()).
|
||||
put('/config').
|
||||
put('/config/patch').
|
||||
reply(200, updated);
|
||||
|
||||
await store.dispatch(Actions.updateConfig(updated));
|
||||
await store.dispatch(Actions.patchConfig(updated));
|
||||
|
||||
state = store.getState();
|
||||
|
||||
|
@ -23,6 +23,7 @@ import type {
|
||||
Team,
|
||||
TeamSearchOpts,
|
||||
} from '@mattermost/types/teams';
|
||||
import type {DeepPartial} from '@mattermost/types/utilities';
|
||||
|
||||
import {AdminTypes} from 'mattermost-redux/action_types';
|
||||
import {getUsersLimits} from 'mattermost-redux/actions/limits';
|
||||
@ -79,9 +80,9 @@ export function getConfig() {
|
||||
});
|
||||
}
|
||||
|
||||
export function updateConfig(config: AdminConfig) {
|
||||
export function patchConfig(config: DeepPartial<AdminConfig>) {
|
||||
return bindClientFunc({
|
||||
clientFunc: Client4.updateConfig,
|
||||
clientFunc: Client4.patchConfig,
|
||||
onSuccess: [AdminTypes.RECEIVED_CONFIG],
|
||||
params: [
|
||||
config,
|
||||
|
@ -8,7 +8,7 @@ export default {
|
||||
PAGE_SIZE_MAXIMUM: 200,
|
||||
LOGS_PAGE_SIZE_DEFAULT: 10000,
|
||||
AUDITS_CHUNK_SIZE: 100,
|
||||
PROFILE_CHUNK_SIZE: 100,
|
||||
PROFILE_CHUNK_SIZE: 100, // WARN: Do not change this without changing the cache key on server side as well. See https://github.com/mattermost/mattermost/pull/26391.
|
||||
CHANNELS_CHUNK_SIZE: 50,
|
||||
TEAMS_CHUNK_SIZE: 50,
|
||||
JOBS_CHUNK_SIZE: 50,
|
||||
|
@ -208,7 +208,7 @@ describe('makeFilterPostsAndAddSeparators', () => {
|
||||
'1010',
|
||||
'1005',
|
||||
'1000',
|
||||
START_OF_NEW_MESSAGES,
|
||||
START_OF_NEW_MESSAGES + (time + 999),
|
||||
'date-' + (today.getTime() + 1000),
|
||||
]);
|
||||
|
||||
@ -217,7 +217,7 @@ describe('makeFilterPostsAndAddSeparators', () => {
|
||||
expect(now).toEqual([
|
||||
'1010',
|
||||
'1005',
|
||||
START_OF_NEW_MESSAGES,
|
||||
START_OF_NEW_MESSAGES + (time + 1003),
|
||||
'1000',
|
||||
'date-' + (today.getTime() + 1000),
|
||||
]);
|
||||
@ -225,7 +225,7 @@ describe('makeFilterPostsAndAddSeparators', () => {
|
||||
now = filterPostsAndAddSeparators(state, {postIds, lastViewedAt: time + 1006, indicateNewMessages: true});
|
||||
expect(now).toEqual([
|
||||
'1010',
|
||||
START_OF_NEW_MESSAGES,
|
||||
START_OF_NEW_MESSAGES + (time + 1006),
|
||||
'1005',
|
||||
'1000',
|
||||
'date-' + (today.getTime() + 1000),
|
||||
@ -296,7 +296,7 @@ describe('makeFilterPostsAndAddSeparators', () => {
|
||||
'1004',
|
||||
'date-' + tomorrow.getTime(),
|
||||
'1003',
|
||||
START_OF_NEW_MESSAGES,
|
||||
START_OF_NEW_MESSAGES + lastViewedAt,
|
||||
'1001',
|
||||
'date-' + today.getTime(),
|
||||
]);
|
||||
@ -304,13 +304,13 @@ describe('makeFilterPostsAndAddSeparators', () => {
|
||||
// No changes
|
||||
let prev = now;
|
||||
now = filterPostsAndAddSeparators(state, {postIds, lastViewedAt, indicateNewMessages: true});
|
||||
expect(now).toEqual(prev);
|
||||
expect(now).toBe(prev);
|
||||
expect(now).toEqual([
|
||||
'1006',
|
||||
'1004',
|
||||
'date-' + tomorrow.getTime(),
|
||||
'1003',
|
||||
START_OF_NEW_MESSAGES,
|
||||
START_OF_NEW_MESSAGES + lastViewedAt,
|
||||
'1001',
|
||||
'date-' + today.getTime(),
|
||||
]);
|
||||
@ -320,13 +320,13 @@ describe('makeFilterPostsAndAddSeparators', () => {
|
||||
|
||||
prev = now;
|
||||
now = filterPostsAndAddSeparators(state, {postIds, lastViewedAt, indicateNewMessages: true});
|
||||
expect(now).toEqual(prev);
|
||||
expect(now).not.toBe(prev);
|
||||
expect(now).toEqual([
|
||||
'1006',
|
||||
'1004',
|
||||
'date-' + tomorrow.getTime(),
|
||||
'1003',
|
||||
START_OF_NEW_MESSAGES,
|
||||
START_OF_NEW_MESSAGES + lastViewedAt,
|
||||
'1001',
|
||||
'date-' + today.getTime(),
|
||||
]);
|
||||
@ -336,11 +336,11 @@ describe('makeFilterPostsAndAddSeparators', () => {
|
||||
|
||||
prev = now;
|
||||
now = filterPostsAndAddSeparators(state, {postIds, lastViewedAt, indicateNewMessages: true});
|
||||
expect(now).not.toEqual(prev);
|
||||
expect(now).not.toBe(prev);
|
||||
expect(now).toEqual([
|
||||
'1006',
|
||||
'1004',
|
||||
START_OF_NEW_MESSAGES,
|
||||
START_OF_NEW_MESSAGES + lastViewedAt,
|
||||
'date-' + tomorrow.getTime(),
|
||||
'1003',
|
||||
'1001',
|
||||
@ -349,11 +349,11 @@ describe('makeFilterPostsAndAddSeparators', () => {
|
||||
|
||||
prev = now;
|
||||
now = filterPostsAndAddSeparators(state, {postIds, lastViewedAt, indicateNewMessages: true});
|
||||
expect(now).toEqual(prev);
|
||||
expect(now).toBe(prev);
|
||||
expect(now).toEqual([
|
||||
'1006',
|
||||
'1004',
|
||||
START_OF_NEW_MESSAGES,
|
||||
START_OF_NEW_MESSAGES + lastViewedAt,
|
||||
'date-' + tomorrow.getTime(),
|
||||
'1003',
|
||||
'1001',
|
||||
@ -365,11 +365,11 @@ describe('makeFilterPostsAndAddSeparators', () => {
|
||||
|
||||
prev = now;
|
||||
now = filterPostsAndAddSeparators(state, {postIds, lastViewedAt, indicateNewMessages: true});
|
||||
expect(now).toEqual(prev);
|
||||
expect(now).toBe(prev);
|
||||
expect(now).toEqual([
|
||||
'1006',
|
||||
'1004',
|
||||
START_OF_NEW_MESSAGES,
|
||||
START_OF_NEW_MESSAGES + lastViewedAt,
|
||||
'date-' + tomorrow.getTime(),
|
||||
'1003',
|
||||
'1001',
|
||||
@ -393,11 +393,11 @@ describe('makeFilterPostsAndAddSeparators', () => {
|
||||
|
||||
prev = now;
|
||||
now = filterPostsAndAddSeparators(state, {postIds, lastViewedAt, indicateNewMessages: true});
|
||||
expect(now).toEqual(prev);
|
||||
expect(now).toBe(prev);
|
||||
expect(now).toEqual([
|
||||
'1006',
|
||||
'1004',
|
||||
START_OF_NEW_MESSAGES,
|
||||
START_OF_NEW_MESSAGES + lastViewedAt,
|
||||
'date-' + tomorrow.getTime(),
|
||||
'1003',
|
||||
'1001',
|
||||
@ -421,11 +421,11 @@ describe('makeFilterPostsAndAddSeparators', () => {
|
||||
|
||||
prev = now;
|
||||
now = filterPostsAndAddSeparators(state, {postIds, lastViewedAt, indicateNewMessages: true});
|
||||
expect(now).toEqual(prev);
|
||||
expect(now).toBe(prev);
|
||||
expect(now).toEqual([
|
||||
'1006',
|
||||
'1004',
|
||||
START_OF_NEW_MESSAGES,
|
||||
START_OF_NEW_MESSAGES + lastViewedAt,
|
||||
'date-' + tomorrow.getTime(),
|
||||
'1003',
|
||||
'1001',
|
||||
@ -453,10 +453,10 @@ describe('makeFilterPostsAndAddSeparators', () => {
|
||||
|
||||
prev = now;
|
||||
now = filterPostsAndAddSeparators(state, {postIds, lastViewedAt, indicateNewMessages: true});
|
||||
expect(now).not.toEqual(prev);
|
||||
expect(now).not.toBe(prev);
|
||||
expect(now).toEqual([
|
||||
'1004',
|
||||
START_OF_NEW_MESSAGES,
|
||||
START_OF_NEW_MESSAGES + lastViewedAt,
|
||||
'date-' + tomorrow.getTime(),
|
||||
'1003',
|
||||
'1001',
|
||||
@ -465,10 +465,10 @@ describe('makeFilterPostsAndAddSeparators', () => {
|
||||
|
||||
prev = now;
|
||||
now = filterPostsAndAddSeparators(state, {postIds, lastViewedAt, indicateNewMessages: true});
|
||||
expect(now).toEqual(prev);
|
||||
expect(now).toBe(prev);
|
||||
expect(now).toEqual([
|
||||
'1004',
|
||||
START_OF_NEW_MESSAGES,
|
||||
START_OF_NEW_MESSAGES + lastViewedAt,
|
||||
'date-' + tomorrow.getTime(),
|
||||
'1003',
|
||||
'1001',
|
||||
@ -908,7 +908,7 @@ describe('getFirstPostId', () => {
|
||||
});
|
||||
|
||||
test('should skip the new message line', () => {
|
||||
expect(getFirstPostId([START_OF_NEW_MESSAGES, 'post2', 'post3', 'post4'])).toBe('post2');
|
||||
expect(getFirstPostId([START_OF_NEW_MESSAGES + '1234', 'post2', 'post3', 'post4'])).toBe('post2');
|
||||
});
|
||||
});
|
||||
|
||||
@ -926,7 +926,7 @@ describe('getLastPostId', () => {
|
||||
});
|
||||
|
||||
test('should skip the new message line', () => {
|
||||
expect(getLastPostId(['post2', 'post3', 'post4', START_OF_NEW_MESSAGES])).toBe('post4');
|
||||
expect(getLastPostId(['post2', 'post3', 'post4', START_OF_NEW_MESSAGES + '1234'])).toBe('post4');
|
||||
});
|
||||
});
|
||||
|
||||
@ -944,7 +944,7 @@ describe('getLastPostIndex', () => {
|
||||
});
|
||||
|
||||
test('should skip the new message line and return index of last post', () => {
|
||||
expect(getLastPostIndex(['post2', 'post3', 'post4', START_OF_NEW_MESSAGES])).toBe(2);
|
||||
expect(getLastPostIndex(['post2', 'post3', 'post4', START_OF_NEW_MESSAGES + '1234'])).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -20,7 +20,7 @@ import {getUserCurrentTimezone} from 'mattermost-redux/utils/timezone_utils';
|
||||
export const COMBINED_USER_ACTIVITY = 'user-activity-';
|
||||
export const CREATE_COMMENT = 'create-comment';
|
||||
export const DATE_LINE = 'date-';
|
||||
export const START_OF_NEW_MESSAGES = 'start-of-new-messages';
|
||||
export const START_OF_NEW_MESSAGES = 'start-of-new-messages-';
|
||||
export const MAX_COMBINED_SYSTEM_POSTS = 100;
|
||||
|
||||
export function shouldShowJoinLeaveMessages(state: GlobalState) {
|
||||
@ -111,7 +111,7 @@ export function makeFilterPostsAndAddSeparators() {
|
||||
!addedNewMessagesIndicator &&
|
||||
indicateNewMessages
|
||||
) {
|
||||
out.push(START_OF_NEW_MESSAGES);
|
||||
out.push(START_OF_NEW_MESSAGES + lastViewedAt);
|
||||
addedNewMessagesIndicator = true;
|
||||
}
|
||||
|
||||
@ -140,7 +140,7 @@ export function makeCombineUserActivityPosts() {
|
||||
for (let i = 0; i < postIds.length; i++) {
|
||||
const postId = postIds[i];
|
||||
|
||||
if (postId === START_OF_NEW_MESSAGES || postId.startsWith(DATE_LINE) || isCreateComment(postId)) {
|
||||
if (isStartOfNewMessages(postId) || isDateLine(postId) || isCreateComment(postId)) {
|
||||
// Not a post, so it won't be combined
|
||||
out.push(postId);
|
||||
|
||||
@ -187,7 +187,15 @@ export function makeCombineUserActivityPosts() {
|
||||
}
|
||||
|
||||
export function isStartOfNewMessages(item: string) {
|
||||
return item === START_OF_NEW_MESSAGES;
|
||||
return item.startsWith(START_OF_NEW_MESSAGES);
|
||||
}
|
||||
|
||||
export function getTimestampForStartOfNewMessages(item: string) {
|
||||
return parseInt(item.substring(START_OF_NEW_MESSAGES.length), 10);
|
||||
}
|
||||
|
||||
export function getNewMessagesIndex(postListIds: string[]): number {
|
||||
return postListIds.findIndex(isStartOfNewMessages);
|
||||
}
|
||||
|
||||
export function isCreateComment(item: string) {
|
||||
|
@ -38,9 +38,37 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
.root-post__divider {
|
||||
position: relative;
|
||||
display: flex;
|
||||
height: 28px;
|
||||
align-items: center;
|
||||
margin: 0 0 4px 30px;
|
||||
|
||||
div {
|
||||
z-index: 1;
|
||||
padding: 0 12px;
|
||||
margin-left: 34px;
|
||||
background: rgba(v(center-channel-bg-rgb), 1);
|
||||
color: rgba(v(center-channel-color-rgb), 0.72);
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
&::before {
|
||||
position: absolute;
|
||||
top: calc(50% - 1px);
|
||||
left: 0;
|
||||
display: block;
|
||||
width: 100%;
|
||||
border-top: 1px solid rgba(var(--center-channel-color-rgb), 0.12);
|
||||
content: "";
|
||||
}
|
||||
}
|
||||
|
||||
.post {
|
||||
&.post--root {
|
||||
padding-top: 2rem;
|
||||
padding-top: 16px;
|
||||
|
||||
.post__body {
|
||||
background: transparent !important;
|
||||
@ -52,9 +80,9 @@
|
||||
}
|
||||
|
||||
.post-pre-header__icons-container {
|
||||
width: 60px; // If the width of post__img changes, this needs to be adjusted accordingly
|
||||
padding-right: 12px; // If the padding of post__img changes, this needs to be adjusted accordingly
|
||||
margin-left: 0; // if left margin of post__content changes, this needs to be adjusted accordingly
|
||||
width: 54px; // If the width of post__img changes, this needs to be adjusted accordingly;
|
||||
padding-right: 12px; // If the padding of post__img changes, this needs to be adjusted accordingly;
|
||||
margin-left: 0; // if left margin of post__content changes, this needs to be adjusted accordingly;
|
||||
}
|
||||
|
||||
.post__header {
|
||||
@ -119,8 +147,8 @@
|
||||
}
|
||||
|
||||
.post__img {
|
||||
width: 60px; // if this changes, the width of post-pre-header__icons-container needs to be adjusted accordingly
|
||||
padding: 2px 12px 0 0; // if the right padding changes, the padding of post-pre-header__icons-container needs to be adjusted accordingly
|
||||
width: 54px; // if this changes, the width of post-pre-header__icons-container needs to be adjusted accordingly;
|
||||
padding: 2px 12px 0 0; // if the right padding changes, the padding of post-pre-header__icons-container needs to be adjusted accordingly;
|
||||
}
|
||||
|
||||
.post-body {
|
||||
|
@ -440,7 +440,7 @@
|
||||
.post {
|
||||
&.post--thread {
|
||||
.post-pre-header__icons-container {
|
||||
width: 60px; // If the width of post__img changes, this needs to be adjusted accordingly
|
||||
width: 44px; // If the width of post__img changes, this needs to be adjusted accordingly
|
||||
padding-right: 12px; // If the padding of post__img changes, this needs to be adjusted accordingly
|
||||
margin-left: 0; // if left margin of post__content changes, this needs to be adjusted accordingly
|
||||
}
|
||||
|
@ -94,6 +94,7 @@ export const getSelectedPost = createSelector(
|
||||
message: localizeMessage('rhs_thread.rootPostDeletedMessage.body', 'Part of this thread has been deleted due to a data retention policy. You can no longer reply to this thread.'),
|
||||
channel_id: selectedPostChannelId,
|
||||
user_id: currentUserId,
|
||||
reply_count: 0,
|
||||
};
|
||||
},
|
||||
);
|
||||
|
@ -16,6 +16,7 @@ export type FakePost = {
|
||||
exists: boolean;
|
||||
type: PostType;
|
||||
message: string;
|
||||
reply_count: number;
|
||||
channel_id: Channel['id'];
|
||||
user_id: UserProfile['id'];
|
||||
};
|
||||
|
@ -1086,6 +1086,7 @@ export const DocLinks = {
|
||||
SITE_URL: 'https://mattermost.com/pl/configure-site-url',
|
||||
SSL_CERTIFICATE: 'https://mattermost.com/pl/setup-ssl-client-certificate',
|
||||
TRUE_UP_REVIEW: 'https://mattermost.com/pl/true-up-documentation',
|
||||
TRUSTED_CONNECTION: 'https://mattermost.com/pl/default-allow-untrusted-internal-connections',
|
||||
UPGRADE_SERVER: 'https://mattermost.com/pl/upgrade-mattermost',
|
||||
};
|
||||
|
||||
|
@ -801,7 +801,7 @@ describe('PostUtils.getOldestPostId', () => {
|
||||
});
|
||||
|
||||
test('Should not return START_OF_NEW_MESSAGES', () => {
|
||||
const postId = PostUtils.getOldestPostId(['postId1', 'postId2', PostListRowListIds.START_OF_NEW_MESSAGES]);
|
||||
const postId = PostUtils.getOldestPostId(['postId1', 'postId2', PostListRowListIds.START_OF_NEW_MESSAGES + 1551711599000]);
|
||||
expect(postId).toEqual('postId2');
|
||||
});
|
||||
});
|
||||
@ -813,7 +813,7 @@ describe('PostUtils.getPreviousPostId', () => {
|
||||
});
|
||||
|
||||
test('Should skip START_OF_NEW_MESSAGES', () => {
|
||||
const postId = PostUtils.getPreviousPostId(['postId1', 'postId2', PostListRowListIds.START_OF_NEW_MESSAGES, 'postId3'], 1);
|
||||
const postId = PostUtils.getPreviousPostId(['postId1', 'postId2', PostListRowListIds.START_OF_NEW_MESSAGES + 1551711599000, 'postId3'], 1);
|
||||
expect(postId).toEqual('postId3');
|
||||
});
|
||||
|
||||
@ -845,7 +845,7 @@ describe('PostUtils.getLatestPostId', () => {
|
||||
});
|
||||
|
||||
test('Should not return START_OF_NEW_MESSAGES', () => {
|
||||
const postId = PostUtils.getLatestPostId([PostListRowListIds.START_OF_NEW_MESSAGES, 'postId1', 'postId2']);
|
||||
const postId = PostUtils.getLatestPostId([PostListRowListIds.START_OF_NEW_MESSAGES + 1551711599000, 'postId1', 'postId2']);
|
||||
expect(postId).toEqual('postId1');
|
||||
});
|
||||
|
||||
|
@ -626,12 +626,6 @@ export function splitMessageBasedOnTextSelection(selectionStart: number, selecti
|
||||
return {firstPiece, lastPiece};
|
||||
}
|
||||
|
||||
export function getNewMessageIndex(postListIds: string[]): number {
|
||||
return postListIds.findIndex(
|
||||
(item) => item.indexOf(PostListRowListIds.START_OF_NEW_MESSAGES) === 0,
|
||||
);
|
||||
}
|
||||
|
||||
export function areConsecutivePostsBySameUser(post: Post, previousPost: Post): boolean {
|
||||
if (!(post && previousPost)) {
|
||||
return false;
|
||||
|
Loading…
Reference in New Issue
Block a user