MM-51482_Create Apps Category and link to bots DM (#22918)

Этот коммит содержится в:
Julian Mondragón
2023-04-27 19:44:14 -05:00
коммит произвёл GitHub
родитель 13f1d0fdc5
Коммит 1051925eec
17 изменённых файлов: 3650 добавлений и 113 удалений

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

@@ -353,9 +353,12 @@ func (*resolver) SidebarCategories(ctx context.Context, args struct {
return nil, appErr return nil, appErr
} }
} else { } else {
appsCategoryEnabled := c.App.Config().FeatureFlags.AppsSidebarCategory
opts := &store.SidebarCategorySearchOpts{ opts := &store.SidebarCategorySearchOpts{
TeamID: args.TeamID, TeamID: args.TeamID,
ExcludeTeam: args.ExcludeTeam, ExcludeTeam: args.ExcludeTeam,
AppsCategoryEnabled: appsCategoryEnabled,
} }
categories, appErr = c.App.GetSidebarCategories(c.AppContext, args.UserID, opts) categories, appErr = c.App.GetSidebarCategories(c.AppContext, args.UserID, opts)
if appErr != nil { if appErr != nil {

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

@@ -25,13 +25,17 @@ func (a *App) createInitialSidebarCategories(userID string, opts *store.SidebarC
func (a *App) GetSidebarCategoriesForTeamForUser(c request.CTX, userID, teamID string) (*model.OrderedSidebarCategories, *model.AppError) { func (a *App) GetSidebarCategoriesForTeamForUser(c request.CTX, userID, teamID string) (*model.OrderedSidebarCategories, *model.AppError) {
var appErr *model.AppError var appErr *model.AppError
categories, err := a.Srv().Store().Channel().GetSidebarCategoriesForTeamForUser(userID, teamID) appsCategoryEnabled := a.Config().FeatureFlags.AppsSidebarCategory
if err == nil && len(categories.Categories) == 0 { options := &store.SidebarCategorySearchOpts{
// A user must always have categories, so migration must not have happened yet, and we should run it ourselves TeamID: teamID,
categories, appErr = a.createInitialSidebarCategories(userID, &store.SidebarCategorySearchOpts{ ExcludeTeam: false,
TeamID: teamID, AppsCategoryEnabled: appsCategoryEnabled,
ExcludeTeam: false, }
}) categories, err := a.Srv().Store().Channel().GetSidebarCategoriesForTeamForUser(userID, teamID, options)
if err == nil && (len(categories.Categories) == 0 || (appsCategoryEnabled && checkMissingSystemSidebarCategories(categories))) {
// A user must always have system categories, so migration must not have happened yet, and we should run it ourselves
categories, appErr = a.createInitialSidebarCategories(userID, options)
if appErr != nil { if appErr != nil {
return nil, appErr return nil, appErr
} }
@@ -52,10 +56,17 @@ func (a *App) GetSidebarCategoriesForTeamForUser(c request.CTX, userID, teamID s
func (a *App) GetSidebarCategories(c request.CTX, userID string, opts *store.SidebarCategorySearchOpts) (*model.OrderedSidebarCategories, *model.AppError) { func (a *App) GetSidebarCategories(c request.CTX, userID string, opts *store.SidebarCategorySearchOpts) (*model.OrderedSidebarCategories, *model.AppError) {
var appErr *model.AppError var appErr *model.AppError
categories, err := a.Srv().Store().Channel().GetSidebarCategories(userID, opts) appsCategoryEnabled := a.Config().FeatureFlags.AppsSidebarCategory
if err == nil && len(categories.Categories) == 0 { options := &store.SidebarCategorySearchOpts{
// A user must always have categories, so migration must not have happened yet, and we should run it ourselves TeamID: opts.TeamID,
categories, appErr = a.createInitialSidebarCategories(userID, opts) ExcludeTeam: opts.ExcludeTeam,
AppsCategoryEnabled: appsCategoryEnabled,
}
categories, err := a.Srv().Store().Channel().GetSidebarCategories(userID, options)
if err == nil && (len(categories.Categories) == 0 || (appsCategoryEnabled && checkMissingSystemSidebarCategories(categories))) {
// A user must always have system categories, so migration must not have happened yet, and we should run it ourselves
categories, appErr = a.createInitialSidebarCategories(userID, options)
if appErr != nil { if appErr != nil {
return nil, appErr return nil, appErr
} }
@@ -90,7 +101,8 @@ func (a *App) GetSidebarCategoryOrder(c request.CTX, userID, teamID string) ([]s
} }
func (a *App) GetSidebarCategory(c request.CTX, categoryId string) (*model.SidebarCategoryWithChannels, *model.AppError) { func (a *App) GetSidebarCategory(c request.CTX, categoryId string) (*model.SidebarCategoryWithChannels, *model.AppError) {
category, err := a.Srv().Store().Channel().GetSidebarCategory(categoryId) appsCategoryEnabled := a.Config().FeatureFlags.AppsSidebarCategory
category, err := a.Srv().Store().Channel().GetSidebarCategory(categoryId, &store.SidebarCategorySearchOpts{AppsCategoryEnabled: appsCategoryEnabled})
if err != nil { if err != nil {
var nfErr *store.ErrNotFound var nfErr *store.ErrNotFound
switch { switch {
@@ -105,7 +117,8 @@ func (a *App) GetSidebarCategory(c request.CTX, categoryId string) (*model.Sideb
} }
func (a *App) CreateSidebarCategory(c request.CTX, userID, teamID string, newCategory *model.SidebarCategoryWithChannels) (*model.SidebarCategoryWithChannels, *model.AppError) { func (a *App) CreateSidebarCategory(c request.CTX, userID, teamID string, newCategory *model.SidebarCategoryWithChannels) (*model.SidebarCategoryWithChannels, *model.AppError) {
category, err := a.Srv().Store().Channel().CreateSidebarCategory(userID, teamID, newCategory) appsCategoryEnabled := a.Config().FeatureFlags.AppsSidebarCategory
category, err := a.Srv().Store().Channel().CreateSidebarCategory(userID, teamID, newCategory, &store.SidebarCategorySearchOpts{AppsCategoryEnabled: appsCategoryEnabled})
if err != nil { if err != nil {
var nfErr *store.ErrNotFound var nfErr *store.ErrNotFound
switch { switch {
@@ -142,7 +155,13 @@ func (a *App) UpdateSidebarCategoryOrder(c request.CTX, userID, teamID string, c
} }
func (a *App) UpdateSidebarCategories(c request.CTX, userID, teamID string, categories []*model.SidebarCategoryWithChannels) ([]*model.SidebarCategoryWithChannels, *model.AppError) { func (a *App) UpdateSidebarCategories(c request.CTX, userID, teamID string, categories []*model.SidebarCategoryWithChannels) ([]*model.SidebarCategoryWithChannels, *model.AppError) {
updatedCategories, originalCategories, err := a.Srv().Store().Channel().UpdateSidebarCategories(userID, teamID, categories) appsCategoryEnabled := a.Config().FeatureFlags.AppsSidebarCategory
updatedCategories, originalCategories, err := a.Srv().Store().Channel().UpdateSidebarCategories(
userID,
teamID,
categories,
&store.SidebarCategorySearchOpts{AppsCategoryEnabled: appsCategoryEnabled},
)
if err != nil { if err != nil {
return nil, model.NewAppError("UpdateSidebarCategories", "app.channel.sidebar_categories.app_error", nil, "", http.StatusInternalServerError).Wrap(err) return nil, model.NewAppError("UpdateSidebarCategories", "app.channel.sidebar_categories.app_error", nil, "", http.StatusInternalServerError).Wrap(err)
} }
@@ -286,3 +305,17 @@ func (a *App) DeleteSidebarCategory(c request.CTX, userID, teamID, categoryId st
return nil return nil
} }
func checkMissingSystemSidebarCategories(categories *model.OrderedSidebarCategories) bool {
missingSystemCategories := make(map[model.SidebarCategoryType]struct{})
for _, systemSidebarCategory := range model.SystemSidebarCategories {
missingSystemCategories[systemSidebarCategory] = struct{}{}
}
for _, category := range categories.Categories {
delete(missingSystemCategories, category.Type)
}
return len(missingSystemCategories) != 0
}

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

@@ -0,0 +1,481 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package app
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/mattermost/mattermost-server/server/v8/model"
)
func TestSidebarCategoryWithAppsCategory(t *testing.T) {
th := Setup(t).InitBasicWithAppsSidebarEnabled()
defer th.TearDown()
basicChannel2 := th.CreateChannel(th.Context, th.BasicTeam)
defer th.App.PermanentDeleteChannel(th.Context, basicChannel2)
user := th.CreateUser()
defer th.App.Srv().Store().User().PermanentDelete(user.Id)
th.LinkUserToTeam(user, th.BasicTeam)
th.AddUserToChannel(user, basicChannel2)
var createdCategory *model.SidebarCategoryWithChannels
t.Run("CreateSidebarCategory", func(t *testing.T) {
catData := model.SidebarCategoryWithChannels{
SidebarCategory: model.SidebarCategory{
DisplayName: "TEST",
},
Channels: []string{th.BasicChannel.Id, basicChannel2.Id, basicChannel2.Id},
}
_, err := th.App.CreateSidebarCategory(th.Context, user.Id, th.BasicTeam.Id, &catData)
require.NotNil(t, err, "Should return error due to duplicate IDs")
catData.Channels = []string{th.BasicChannel.Id, basicChannel2.Id}
cat, err := th.App.CreateSidebarCategory(th.Context, user.Id, th.BasicTeam.Id, &catData)
require.Nil(t, err, "Expected no error")
require.NotNil(t, cat, "Expected category object, got nil")
createdCategory = cat
})
t.Run("UpdateSidebarCategories", func(t *testing.T) {
require.NotNil(t, createdCategory)
createdCategory.Channels = []string{th.BasicChannel.Id}
updatedCat, err := th.App.UpdateSidebarCategories(th.Context, user.Id, th.BasicTeam.Id, []*model.SidebarCategoryWithChannels{createdCategory})
require.Nil(t, err, "Expected no error")
require.NotNil(t, updatedCat, "Expected category object, got nil")
require.Len(t, updatedCat, 1)
require.Len(t, updatedCat[0].Channels, 1)
require.Equal(t, updatedCat[0].Channels[0], th.BasicChannel.Id)
})
t.Run("UpdateSidebarCategoryOrder", func(t *testing.T) {
err := th.App.UpdateSidebarCategoryOrder(th.Context, user.Id, th.BasicTeam.Id, []string{th.BasicChannel.Id, basicChannel2.Id})
require.NotNil(t, err, "Should return error due to invalid order")
actualOrder, err := th.App.GetSidebarCategoryOrder(th.Context, user.Id, th.BasicTeam.Id)
require.Nil(t, err, "Should fetch order successfully")
actualOrder[2], actualOrder[3] = actualOrder[3], actualOrder[2]
err = th.App.UpdateSidebarCategoryOrder(th.Context, user.Id, th.BasicTeam.Id, actualOrder)
require.Nil(t, err, "Should update order successfully")
// We create a copy of actualOrder to prevent racy read
// of the slice when the broadcast message is sent from webhub.
newOrder := make([]string, len(actualOrder))
copy(newOrder, actualOrder)
newOrder[2] = "asd"
err = th.App.UpdateSidebarCategoryOrder(th.Context, user.Id, th.BasicTeam.Id, newOrder)
require.NotNil(t, err, "Should return error due to invalid id")
})
t.Run("GetSidebarCategoryOrder", func(t *testing.T) {
catOrder, err := th.App.GetSidebarCategoryOrder(th.Context, user.Id, th.BasicTeam.Id)
require.Nil(t, err, "Expected no error")
require.Len(t, catOrder, 5)
require.Equal(t, catOrder[1], createdCategory.Id, "the newly created category should be after favorites")
})
}
func TestGetSidebarCategoriesWithAppsCategory(t *testing.T) {
t.Run("should return the sidebar categories for the given user/team", func(t *testing.T) {
th := Setup(t).InitBasicWithAppsSidebarEnabled()
defer th.TearDown()
_, err := th.App.CreateSidebarCategory(th.Context, th.BasicUser.Id, th.BasicTeam.Id, &model.SidebarCategoryWithChannels{
SidebarCategory: model.SidebarCategory{
UserId: th.BasicUser.Id,
TeamId: th.BasicTeam.Id,
DisplayName: "new category",
},
})
require.Nil(t, err)
categories, err := th.App.GetSidebarCategoriesForTeamForUser(th.Context, th.BasicUser.Id, th.BasicTeam.Id)
assert.Nil(t, err)
assert.Len(t, categories.Categories, 5)
})
t.Run("should create the initial categories even if migration hasn't ran yet", func(t *testing.T) {
th := Setup(t).InitBasicWithAppsSidebarEnabled()
defer th.TearDown()
// Manually add the user to the team without going through the app layer to simulate a pre-existing user/team
// relationship that hasn't been migrated yet
team := th.CreateTeam()
_, err := th.App.Srv().Store().Team().SaveMember(&model.TeamMember{
TeamId: team.Id,
UserId: th.BasicUser.Id,
SchemeUser: true,
}, 100)
require.NoError(t, err)
categories, appErr := th.App.GetSidebarCategoriesForTeamForUser(th.Context, th.BasicUser.Id, team.Id)
assert.Nil(t, appErr)
assert.Len(t, categories.Categories, 4)
})
t.Run("should return a store error if a db table is missing", func(t *testing.T) {
th := Setup(t).InitBasicWithAppsSidebarEnabled()
defer th.TearDown()
// Temporarily renaming a table to force a DB error.
sqlStore := mainHelper.GetSQLStore()
_, err := sqlStore.GetMasterX().Exec("ALTER TABLE SidebarCategories RENAME TO SidebarCategoriesTest")
require.NoError(t, err)
defer func() {
_, err := sqlStore.GetMasterX().Exec("ALTER TABLE SidebarCategoriesTest RENAME TO SidebarCategories")
require.NoError(t, err)
}()
categories, appErr := th.App.GetSidebarCategoriesForTeamForUser(th.Context, th.BasicUser.Id, th.BasicTeam.Id)
assert.Nil(t, categories)
assert.NotNil(t, appErr)
assert.Equal(t, "app.channel.sidebar_categories.app_error", appErr.Id)
})
}
func TestUpdateSidebarCategoriesWithAppsCategory(t *testing.T) {
t.Run("should mute and unmute all channels in a category when it is muted or unmuted", func(t *testing.T) {
th := Setup(t).InitBasicWithAppsSidebarEnabled()
defer th.TearDown()
categories, err := th.App.GetSidebarCategoriesForTeamForUser(th.Context, th.BasicUser.Id, th.BasicTeam.Id)
require.Nil(t, err)
channelsCategory := categories.Categories[1]
// Create some channels to be part of the channels category
channel1 := th.CreateChannel(th.Context, th.BasicTeam)
th.AddUserToChannel(th.BasicUser, channel1)
channel2 := th.CreateChannel(th.Context, th.BasicTeam)
th.AddUserToChannel(th.BasicUser, channel2)
// Mute the category
updated, err := th.App.UpdateSidebarCategories(th.Context, th.BasicUser.Id, th.BasicTeam.Id, []*model.SidebarCategoryWithChannels{
{
SidebarCategory: model.SidebarCategory{
Id: channelsCategory.Id,
Muted: true,
},
Channels: []string{channel1.Id, channel2.Id},
},
})
require.Nil(t, err)
assert.True(t, updated[0].Muted)
// Confirm that the channels are now muted
member1, err := th.App.GetChannelMember(th.Context, channel1.Id, th.BasicUser.Id)
require.Nil(t, err)
assert.True(t, member1.IsChannelMuted())
member2, err := th.App.GetChannelMember(th.Context, channel2.Id, th.BasicUser.Id)
require.Nil(t, err)
assert.True(t, member2.IsChannelMuted())
// Unmute the category
updated, err = th.App.UpdateSidebarCategories(th.Context, th.BasicUser.Id, th.BasicTeam.Id, []*model.SidebarCategoryWithChannels{
{
SidebarCategory: model.SidebarCategory{
Id: channelsCategory.Id,
Muted: false,
},
Channels: []string{channel1.Id, channel2.Id},
},
})
require.Nil(t, err)
assert.False(t, updated[0].Muted)
// Confirm that the channels are now unmuted
member1, err = th.App.GetChannelMember(th.Context, channel1.Id, th.BasicUser.Id)
require.Nil(t, err)
assert.False(t, member1.IsChannelMuted())
member2, err = th.App.GetChannelMember(th.Context, channel2.Id, th.BasicUser.Id)
require.Nil(t, err)
assert.False(t, member2.IsChannelMuted())
})
t.Run("should mute and unmute channels moved from an unmuted category to a muted one and back", func(t *testing.T) {
th := Setup(t).InitBasicWithAppsSidebarEnabled()
defer th.TearDown()
// Create some channels
channel1 := th.CreateChannel(th.Context, th.BasicTeam)
th.AddUserToChannel(th.BasicUser, channel1)
channel2 := th.CreateChannel(th.Context, th.BasicTeam)
th.AddUserToChannel(th.BasicUser, channel2)
// And some categories
mutedCategory, err := th.App.CreateSidebarCategory(th.Context, th.BasicUser.Id, th.BasicTeam.Id, &model.SidebarCategoryWithChannels{
SidebarCategory: model.SidebarCategory{
DisplayName: "muted",
Muted: true,
},
})
require.Nil(t, err)
require.True(t, mutedCategory.Muted)
unmutedCategory, err := th.App.CreateSidebarCategory(th.Context, th.BasicUser.Id, th.BasicTeam.Id, &model.SidebarCategoryWithChannels{
SidebarCategory: model.SidebarCategory{
DisplayName: "unmuted",
Muted: false,
},
Channels: []string{channel1.Id, channel2.Id},
})
require.Nil(t, err)
require.False(t, unmutedCategory.Muted)
// Move the channels
_, err = th.App.UpdateSidebarCategories(th.Context, th.BasicUser.Id, th.BasicTeam.Id, []*model.SidebarCategoryWithChannels{
{
SidebarCategory: model.SidebarCategory{
Id: mutedCategory.Id,
DisplayName: mutedCategory.DisplayName,
Muted: mutedCategory.Muted,
},
Channels: []string{channel1.Id, channel2.Id},
},
{
SidebarCategory: model.SidebarCategory{
Id: unmutedCategory.Id,
DisplayName: unmutedCategory.DisplayName,
Muted: unmutedCategory.Muted,
},
Channels: []string{},
},
})
require.Nil(t, err)
// Confirm that the channels are now muted
member1, err := th.App.GetChannelMember(th.Context, channel1.Id, th.BasicUser.Id)
require.Nil(t, err)
assert.True(t, member1.IsChannelMuted())
member2, err := th.App.GetChannelMember(th.Context, channel2.Id, th.BasicUser.Id)
require.Nil(t, err)
assert.True(t, member2.IsChannelMuted())
// Move the channels back
_, err = th.App.UpdateSidebarCategories(th.Context, th.BasicUser.Id, th.BasicTeam.Id, []*model.SidebarCategoryWithChannels{
{
SidebarCategory: model.SidebarCategory{
Id: mutedCategory.Id,
DisplayName: mutedCategory.DisplayName,
Muted: mutedCategory.Muted,
},
Channels: []string{},
},
{
SidebarCategory: model.SidebarCategory{
Id: unmutedCategory.Id,
DisplayName: unmutedCategory.DisplayName,
Muted: unmutedCategory.Muted,
},
Channels: []string{channel1.Id, channel2.Id},
},
})
require.Nil(t, err)
// Confirm that the channels are now unmuted
member1, err = th.App.GetChannelMember(th.Context, channel1.Id, th.BasicUser.Id)
require.Nil(t, err)
assert.False(t, member1.IsChannelMuted())
member2, err = th.App.GetChannelMember(th.Context, channel2.Id, th.BasicUser.Id)
require.Nil(t, err)
assert.False(t, member2.IsChannelMuted())
})
t.Run("should not mute or unmute channels moved between muted categories", func(t *testing.T) {
th := Setup(t).InitBasicWithAppsSidebarEnabled()
defer th.TearDown()
// Create some channels
channel1 := th.CreateChannel(th.Context, th.BasicTeam)
th.AddUserToChannel(th.BasicUser, channel1)
channel2 := th.CreateChannel(th.Context, th.BasicTeam)
th.AddUserToChannel(th.BasicUser, channel2)
// And some categories
category1, err := th.App.CreateSidebarCategory(th.Context, th.BasicUser.Id, th.BasicTeam.Id, &model.SidebarCategoryWithChannels{
SidebarCategory: model.SidebarCategory{
DisplayName: "category1",
Muted: true,
},
})
require.Nil(t, err)
require.True(t, category1.Muted)
category2, err := th.App.CreateSidebarCategory(th.Context, th.BasicUser.Id, th.BasicTeam.Id, &model.SidebarCategoryWithChannels{
SidebarCategory: model.SidebarCategory{
DisplayName: "category2",
Muted: true,
},
Channels: []string{channel1.Id, channel2.Id},
})
require.Nil(t, err)
require.True(t, category2.Muted)
// Move the unmuted channels
_, err = th.App.UpdateSidebarCategories(th.Context, th.BasicUser.Id, th.BasicTeam.Id, []*model.SidebarCategoryWithChannels{
{
SidebarCategory: model.SidebarCategory{
Id: category1.Id,
DisplayName: category1.DisplayName,
Muted: category1.Muted,
},
Channels: []string{channel1.Id, channel2.Id},
},
{
SidebarCategory: model.SidebarCategory{
Id: category2.Id,
DisplayName: category2.DisplayName,
Muted: category2.Muted,
},
Channels: []string{},
},
})
require.Nil(t, err)
// Confirm that the channels are still unmuted
member1, err := th.App.GetChannelMember(th.Context, channel1.Id, th.BasicUser.Id)
require.Nil(t, err)
assert.False(t, member1.IsChannelMuted())
member2, err := th.App.GetChannelMember(th.Context, channel2.Id, th.BasicUser.Id)
require.Nil(t, err)
assert.False(t, member2.IsChannelMuted())
// Mute the channels manually
_, err = th.App.ToggleMuteChannel(th.Context, channel1.Id, th.BasicUser.Id)
require.Nil(t, err)
_, err = th.App.ToggleMuteChannel(th.Context, channel2.Id, th.BasicUser.Id)
require.Nil(t, err)
// Move the muted channels back
_, err = th.App.UpdateSidebarCategories(th.Context, th.BasicUser.Id, th.BasicTeam.Id, []*model.SidebarCategoryWithChannels{
{
SidebarCategory: model.SidebarCategory{
Id: category1.Id,
DisplayName: category1.DisplayName,
Muted: category1.Muted,
},
Channels: []string{},
},
{
SidebarCategory: model.SidebarCategory{
Id: category2.Id,
DisplayName: category2.DisplayName,
Muted: category2.Muted,
},
Channels: []string{channel1.Id, channel2.Id},
},
})
require.Nil(t, err)
// Confirm that the channels are still muted
member1, err = th.App.GetChannelMember(th.Context, channel1.Id, th.BasicUser.Id)
require.Nil(t, err)
assert.True(t, member1.IsChannelMuted())
member2, err = th.App.GetChannelMember(th.Context, channel2.Id, th.BasicUser.Id)
require.Nil(t, err)
assert.True(t, member2.IsChannelMuted())
})
t.Run("should not mute or unmute channels moved between unmuted categories", func(t *testing.T) {
th := Setup(t).InitBasicWithAppsSidebarEnabled()
defer th.TearDown()
// Create some channels
channel1 := th.CreateChannel(th.Context, th.BasicTeam)
th.AddUserToChannel(th.BasicUser, channel1)
channel2 := th.CreateChannel(th.Context, th.BasicTeam)
th.AddUserToChannel(th.BasicUser, channel2)
// And some categories
category1, err := th.App.CreateSidebarCategory(th.Context, th.BasicUser.Id, th.BasicTeam.Id, &model.SidebarCategoryWithChannels{
SidebarCategory: model.SidebarCategory{
DisplayName: "category1",
Muted: false,
},
})
require.Nil(t, err)
require.False(t, category1.Muted)
category2, err := th.App.CreateSidebarCategory(th.Context, th.BasicUser.Id, th.BasicTeam.Id, &model.SidebarCategoryWithChannels{
SidebarCategory: model.SidebarCategory{
DisplayName: "category2",
Muted: false,
},
Channels: []string{channel1.Id, channel2.Id},
})
require.Nil(t, err)
require.False(t, category2.Muted)
// Move the unmuted channels
_, err = th.App.UpdateSidebarCategories(th.Context, th.BasicUser.Id, th.BasicTeam.Id, []*model.SidebarCategoryWithChannels{
{
SidebarCategory: model.SidebarCategory{
Id: category1.Id,
DisplayName: category1.DisplayName,
Muted: category1.Muted,
},
Channels: []string{channel1.Id, channel2.Id},
},
{
SidebarCategory: model.SidebarCategory{
Id: category2.Id,
DisplayName: category2.DisplayName,
Muted: category2.Muted,
},
Channels: []string{},
},
})
require.Nil(t, err)
// Confirm that the channels are still unmuted
member1, err := th.App.GetChannelMember(th.Context, channel1.Id, th.BasicUser.Id)
require.Nil(t, err)
assert.False(t, member1.IsChannelMuted())
member2, err := th.App.GetChannelMember(th.Context, channel2.Id, th.BasicUser.Id)
require.Nil(t, err)
assert.False(t, member2.IsChannelMuted())
// Mute the channels manually
_, err = th.App.ToggleMuteChannel(th.Context, channel1.Id, th.BasicUser.Id)
require.Nil(t, err)
_, err = th.App.ToggleMuteChannel(th.Context, channel2.Id, th.BasicUser.Id)
require.Nil(t, err)
// Move the muted channels back
_, err = th.App.UpdateSidebarCategories(th.Context, th.BasicUser.Id, th.BasicTeam.Id, []*model.SidebarCategoryWithChannels{
{
SidebarCategory: model.SidebarCategory{
Id: category1.Id,
DisplayName: category1.DisplayName,
Muted: category1.Muted,
},
Channels: []string{},
},
{
SidebarCategory: model.SidebarCategory{
Id: category2.Id,
DisplayName: category2.DisplayName,
Muted: category2.Muted,
},
Channels: []string{channel1.Id, channel2.Id},
},
})
require.Nil(t, err)
// Confirm that the channels are still muted
member1, err = th.App.GetChannelMember(th.Context, channel1.Id, th.BasicUser.Id)
require.Nil(t, err)
assert.True(t, member1.IsChannelMuted())
member2, err = th.App.GetChannelMember(th.Context, channel2.Id, th.BasicUser.Id)
require.Nil(t, err)
assert.True(t, member2.IsChannelMuted())
})
}

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

@@ -253,6 +253,12 @@ func (th *TestHelper) InitBasic() *TestHelper {
return th return th
} }
func (th *TestHelper) InitBasicWithAppsSidebarEnabled() *TestHelper {
th.App.Config().FeatureFlags.AppsSidebarCategory = true
return th.InitBasic()
}
func (th *TestHelper) DeleteBots() *TestHelper { func (th *TestHelper) DeleteBots() *TestHelper {
preexistingBots, _ := th.App.GetBots(&model.BotGetOptions{Page: 0, PerPage: 100}) preexistingBots, _ := th.App.GetBots(&model.BotGetOptions{Page: 0, PerPage: 100})
for _, bot := range preexistingBots { for _, bot := range preexistingBots {

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

@@ -956,9 +956,11 @@ func (a *App) JoinUserToTeam(c request.CTX, team *model.Team, user *model.User,
return nil, model.NewAppError("JoinUserToTeam", "app.user.update_update.app_error", nil, "", http.StatusInternalServerError).Wrap(err) return nil, model.NewAppError("JoinUserToTeam", "app.user.update_update.app_error", nil, "", http.StatusInternalServerError).Wrap(err)
} }
appsCategoryEnabled := a.Config().FeatureFlags.AppsSidebarCategory
opts := &store.SidebarCategorySearchOpts{ opts := &store.SidebarCategorySearchOpts{
TeamID: team.Id, TeamID: team.Id,
ExcludeTeam: false, ExcludeTeam: false,
AppsCategoryEnabled: appsCategoryEnabled,
} }
if _, err := a.createInitialSidebarCategories(user.Id, opts); err != nil { if _, err := a.createInitialSidebarCategories(user.Id, opts); err != nil {
mlog.Warn( mlog.Warn(

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

@@ -1025,6 +1025,119 @@ func TestJoinUserToTeam(t *testing.T) {
}) })
} }
func TestJoinUserToTeamWithAppsCategoryEnabled(t *testing.T) {
th := Setup(t)
defer th.TearDown()
th.App.UpdateConfig(func(cfg *model.Config) { cfg.FeatureFlags.AppsSidebarCategory = true })
id := model.NewId()
team := &model.Team{
DisplayName: "dn_" + id,
Name: "name" + id,
Email: "success+" + id + "@simulator.amazonses.com",
Type: model.TeamOpen,
}
_, err := th.App.CreateTeam(th.Context, team)
require.Nil(t, err, "Should create a new team")
maxUsersPerTeam := th.App.Config().TeamSettings.MaxUsersPerTeam
defer func() {
th.App.UpdateConfig(func(cfg *model.Config) { cfg.TeamSettings.MaxUsersPerTeam = maxUsersPerTeam })
th.App.PermanentDeleteTeam(th.Context, team)
}()
one := 1
th.App.UpdateConfig(func(cfg *model.Config) { cfg.TeamSettings.MaxUsersPerTeam = &one })
t.Run("new join", func(t *testing.T) {
user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Darth Vader", Username: "vader" + model.NewId(), Password: "passwd1", AuthService: ""}
ruser, _ := th.App.CreateUser(th.Context, &user)
defer th.App.PermanentDeleteUser(th.Context, &user)
_, appErr := th.App.JoinUserToTeam(th.Context, team, ruser, "")
require.Nil(t, appErr, "Should return no error")
})
t.Run("new join with limit problem", func(t *testing.T) {
user1 := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Darth Vader", Username: "vader" + model.NewId(), Password: "passwd1", AuthService: ""}
ruser1, _ := th.App.CreateUser(th.Context, &user1)
user2 := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Darth Vader", Username: "vader" + model.NewId(), Password: "passwd1", AuthService: ""}
ruser2, _ := th.App.CreateUser(th.Context, &user2)
defer th.App.PermanentDeleteUser(th.Context, &user1)
defer th.App.PermanentDeleteUser(th.Context, &user2)
_, appErr := th.App.JoinUserToTeam(th.Context, team, ruser1, ruser2.Id)
require.Nil(t, appErr, "Should return no error")
_, appErr = th.App.JoinUserToTeam(th.Context, team, ruser2, ruser1.Id)
require.NotNil(t, appErr, "Should fail")
})
t.Run("re-join after leaving with limit problem", func(t *testing.T) {
user1 := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Darth Vader", Username: "vader" + model.NewId(), Password: "passwd1", AuthService: ""}
ruser1, _ := th.App.CreateUser(th.Context, &user1)
user2 := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Darth Vader", Username: "vader" + model.NewId(), Password: "passwd1", AuthService: ""}
ruser2, _ := th.App.CreateUser(th.Context, &user2)
defer th.App.PermanentDeleteUser(th.Context, &user1)
defer th.App.PermanentDeleteUser(th.Context, &user2)
_, appErr := th.App.JoinUserToTeam(th.Context, team, ruser1, ruser2.Id)
require.Nil(t, appErr, "Should return no error")
appErr = th.App.LeaveTeam(th.Context, team, ruser1, ruser1.Id)
require.Nil(t, appErr, "Should return no error")
_, appErr = th.App.JoinUserToTeam(th.Context, team, ruser2, ruser2.Id)
require.Nil(t, appErr, "Should return no error")
_, appErr = th.App.JoinUserToTeam(th.Context, team, ruser1, ruser2.Id)
require.NotNil(t, appErr, "Should fail")
})
t.Run("new join with correct scheme_admin value from group syncable", func(t *testing.T) {
user1 := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Darth Vader", Username: "vader" + model.NewId(), Password: "passwd1", AuthService: ""}
ruser1, _ := th.App.CreateUser(th.Context, &user1)
defer th.App.PermanentDeleteUser(th.Context, &user1)
group := th.CreateGroup()
_, err = th.App.UpsertGroupMember(group.Id, user1.Id)
require.Nil(t, err)
gs, err := th.App.UpsertGroupSyncable(&model.GroupSyncable{
AutoAdd: true,
SyncableId: team.Id,
Type: model.GroupSyncableTypeTeam,
GroupId: group.Id,
SchemeAdmin: false,
})
require.Nil(t, err)
th.App.UpdateConfig(func(cfg *model.Config) { cfg.TeamSettings.MaxUsersPerTeam = model.NewInt(999) })
tm1, appErr := th.App.JoinUserToTeam(th.Context, team, ruser1, "")
require.Nil(t, appErr)
require.False(t, tm1.SchemeAdmin)
user2 := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Darth Vader", Username: "vader" + model.NewId(), Password: "passwd1", AuthService: ""}
ruser2, _ := th.App.CreateUser(th.Context, &user2)
defer th.App.PermanentDeleteUser(th.Context, &user2)
_, err = th.App.UpsertGroupMember(group.Id, user2.Id)
require.Nil(t, err)
gs.SchemeAdmin = true
_, err = th.App.UpdateGroupSyncable(gs)
require.Nil(t, err)
tm2, appErr := th.App.JoinUserToTeam(th.Context, team, ruser2, "")
require.Nil(t, appErr)
require.True(t, tm2.SchemeAdmin)
})
}
func TestLeaveTeamPanic(t *testing.T) { func TestLeaveTeamPanic(t *testing.T) {
th := SetupWithStoreMock(t) th := SetupWithStoreMock(t)
defer th.TearDown() defer th.TearDown()

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

@@ -296,6 +296,8 @@ func generateLayer(name, templateFile string) ([]byte, error) {
paramsWithType = append(paramsWithType, fmt.Sprintf("%s store.%s", param.Name, param.Type)) paramsWithType = append(paramsWithType, fmt.Sprintf("%s store.%s", param.Name, param.Type))
case "*UserGetByIdsOpts", "*ChannelMemberGraphQLSearchOpts", "*SidebarCategorySearchOpts": case "*UserGetByIdsOpts", "*ChannelMemberGraphQLSearchOpts", "*SidebarCategorySearchOpts":
paramsWithType = append(paramsWithType, fmt.Sprintf("%s *store.%s", param.Name, strings.TrimPrefix(param.Type, "*"))) paramsWithType = append(paramsWithType, fmt.Sprintf("%s *store.%s", param.Name, strings.TrimPrefix(param.Type, "*")))
case "...*SidebarCategorySearchOpts":
paramsWithType = append(paramsWithType, fmt.Sprintf("%s ...*store.%s", param.Name, strings.TrimPrefix(param.Type, "...*")))
default: default:
paramsWithType = append(paramsWithType, fmt.Sprintf("%s %s", param.Name, param.Type)) paramsWithType = append(paramsWithType, fmt.Sprintf("%s %s", param.Name, param.Type))
} }
@@ -310,6 +312,8 @@ func generateLayer(name, templateFile string) ([]byte, error) {
paramsWithType = append(paramsWithType, fmt.Sprintf("%s store.%s", param.Name, param.Type)) paramsWithType = append(paramsWithType, fmt.Sprintf("%s store.%s", param.Name, param.Type))
case "*UserGetByIdsOpts", "*ChannelMemberGraphQLSearchOpts", "*SidebarCategorySearchOpts": case "*UserGetByIdsOpts", "*ChannelMemberGraphQLSearchOpts", "*SidebarCategorySearchOpts":
paramsWithType = append(paramsWithType, fmt.Sprintf("%s *store.%s", param.Name, strings.TrimPrefix(param.Type, "*"))) paramsWithType = append(paramsWithType, fmt.Sprintf("%s *store.%s", param.Name, strings.TrimPrefix(param.Type, "*")))
case "...*SidebarCategorySearchOpts":
paramsWithType = append(paramsWithType, fmt.Sprintf("%s ...*store.%s", param.Name, strings.TrimPrefix(param.Type, "...*")))
default: default:
paramsWithType = append(paramsWithType, fmt.Sprintf("%s %s", param.Name, param.Type)) paramsWithType = append(paramsWithType, fmt.Sprintf("%s %s", param.Name, param.Type))
} }

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

@@ -809,7 +809,7 @@ func (s *OpenTracingLayerChannelStore) CreateInitialSidebarCategories(userID str
return result, err return result, err
} }
func (s *OpenTracingLayerChannelStore) CreateSidebarCategory(userID string, teamID string, newCategory *model.SidebarCategoryWithChannels) (*model.SidebarCategoryWithChannels, error) { func (s *OpenTracingLayerChannelStore) CreateSidebarCategory(userID string, teamID string, newCategory *model.SidebarCategoryWithChannels, options ...*store.SidebarCategorySearchOpts) (*model.SidebarCategoryWithChannels, error) {
origCtx := s.Root.Store.Context() origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.CreateSidebarCategory") span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.CreateSidebarCategory")
s.Root.Store.SetContext(newCtx) s.Root.Store.SetContext(newCtx)
@@ -818,7 +818,7 @@ func (s *OpenTracingLayerChannelStore) CreateSidebarCategory(userID string, team
}() }()
defer span.Finish() defer span.Finish()
result, err := s.ChannelStore.CreateSidebarCategory(userID, teamID, newCategory) result, err := s.ChannelStore.CreateSidebarCategory(userID, teamID, newCategory, options...)
if err != nil { if err != nil {
span.LogFields(spanlog.Error(err)) span.LogFields(spanlog.Error(err))
ext.Error.Set(span, true) ext.Error.Set(span, true)
@@ -1043,6 +1043,24 @@ func (s *OpenTracingLayerChannelStore) GetAllDirectChannelsForExportAfter(limit
return result, err return result, err
} }
func (s *OpenTracingLayerChannelStore) GetBotChannelsByUser(userID string, opts store.ChannelSearchOpts) (model.ChannelList, error) {
origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.GetBotChannelsByUser")
s.Root.Store.SetContext(newCtx)
defer func() {
s.Root.Store.SetContext(origCtx)
}()
defer span.Finish()
result, err := s.ChannelStore.GetBotChannelsByUser(userID, opts)
if err != nil {
span.LogFields(spanlog.Error(err))
ext.Error.Set(span, true)
}
return result, err
}
func (s *OpenTracingLayerChannelStore) GetByName(team_id string, name string, allowFromCache bool) (*model.Channel, error) { func (s *OpenTracingLayerChannelStore) GetByName(team_id string, name string, allowFromCache bool) (*model.Channel, error) {
origCtx := s.Root.Store.Context() origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.GetByName") span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.GetByName")
@@ -1740,7 +1758,7 @@ func (s *OpenTracingLayerChannelStore) GetSidebarCategories(userID string, opts
return result, err return result, err
} }
func (s *OpenTracingLayerChannelStore) GetSidebarCategoriesForTeamForUser(userID string, teamID string) (*model.OrderedSidebarCategories, error) { func (s *OpenTracingLayerChannelStore) GetSidebarCategoriesForTeamForUser(userID string, teamID string, options ...*store.SidebarCategorySearchOpts) (*model.OrderedSidebarCategories, error) {
origCtx := s.Root.Store.Context() origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.GetSidebarCategoriesForTeamForUser") span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.GetSidebarCategoriesForTeamForUser")
s.Root.Store.SetContext(newCtx) s.Root.Store.SetContext(newCtx)
@@ -1749,7 +1767,7 @@ func (s *OpenTracingLayerChannelStore) GetSidebarCategoriesForTeamForUser(userID
}() }()
defer span.Finish() defer span.Finish()
result, err := s.ChannelStore.GetSidebarCategoriesForTeamForUser(userID, teamID) result, err := s.ChannelStore.GetSidebarCategoriesForTeamForUser(userID, teamID, options...)
if err != nil { if err != nil {
span.LogFields(spanlog.Error(err)) span.LogFields(spanlog.Error(err))
ext.Error.Set(span, true) ext.Error.Set(span, true)
@@ -1758,7 +1776,7 @@ func (s *OpenTracingLayerChannelStore) GetSidebarCategoriesForTeamForUser(userID
return result, err return result, err
} }
func (s *OpenTracingLayerChannelStore) GetSidebarCategory(categoryID string) (*model.SidebarCategoryWithChannels, error) { func (s *OpenTracingLayerChannelStore) GetSidebarCategory(categoryID string, options ...*store.SidebarCategorySearchOpts) (*model.SidebarCategoryWithChannels, error) {
origCtx := s.Root.Store.Context() origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.GetSidebarCategory") span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.GetSidebarCategory")
s.Root.Store.SetContext(newCtx) s.Root.Store.SetContext(newCtx)
@@ -1767,7 +1785,7 @@ func (s *OpenTracingLayerChannelStore) GetSidebarCategory(categoryID string) (*m
}() }()
defer span.Finish() defer span.Finish()
result, err := s.ChannelStore.GetSidebarCategory(categoryID) result, err := s.ChannelStore.GetSidebarCategory(categoryID, options...)
if err != nil { if err != nil {
span.LogFields(spanlog.Error(err)) span.LogFields(spanlog.Error(err))
ext.Error.Set(span, true) ext.Error.Set(span, true)
@@ -2600,7 +2618,7 @@ func (s *OpenTracingLayerChannelStore) UpdateMultipleMembers(members []*model.Ch
return result, err return result, err
} }
func (s *OpenTracingLayerChannelStore) UpdateSidebarCategories(userID string, teamID string, categories []*model.SidebarCategoryWithChannels) ([]*model.SidebarCategoryWithChannels, []*model.SidebarCategoryWithChannels, error) { func (s *OpenTracingLayerChannelStore) UpdateSidebarCategories(userID string, teamID string, categories []*model.SidebarCategoryWithChannels, options ...*store.SidebarCategorySearchOpts) ([]*model.SidebarCategoryWithChannels, []*model.SidebarCategoryWithChannels, error) {
origCtx := s.Root.Store.Context() origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.UpdateSidebarCategories") span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.UpdateSidebarCategories")
s.Root.Store.SetContext(newCtx) s.Root.Store.SetContext(newCtx)
@@ -2609,7 +2627,7 @@ func (s *OpenTracingLayerChannelStore) UpdateSidebarCategories(userID string, te
}() }()
defer span.Finish() defer span.Finish()
result, resultVar1, err := s.ChannelStore.UpdateSidebarCategories(userID, teamID, categories) result, resultVar1, err := s.ChannelStore.UpdateSidebarCategories(userID, teamID, categories, options...)
if err != nil { if err != nil {
span.LogFields(spanlog.Error(err)) span.LogFields(spanlog.Error(err))
ext.Error.Set(span, true) ext.Error.Set(span, true)

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

@@ -871,11 +871,11 @@ func (s *RetryLayerChannelStore) CreateInitialSidebarCategories(userID string, o
} }
func (s *RetryLayerChannelStore) CreateSidebarCategory(userID string, teamID string, newCategory *model.SidebarCategoryWithChannels) (*model.SidebarCategoryWithChannels, error) { func (s *RetryLayerChannelStore) CreateSidebarCategory(userID string, teamID string, newCategory *model.SidebarCategoryWithChannels, options ...*store.SidebarCategorySearchOpts) (*model.SidebarCategoryWithChannels, error) {
tries := 0 tries := 0
for { for {
result, err := s.ChannelStore.CreateSidebarCategory(userID, teamID, newCategory) result, err := s.ChannelStore.CreateSidebarCategory(userID, teamID, newCategory, options...)
if err == nil { if err == nil {
return result, nil return result, nil
} }
@@ -1144,6 +1144,27 @@ func (s *RetryLayerChannelStore) GetAllDirectChannelsForExportAfter(limit int, a
} }
func (s *RetryLayerChannelStore) GetBotChannelsByUser(userID string, opts store.ChannelSearchOpts) (model.ChannelList, error) {
tries := 0
for {
result, err := s.ChannelStore.GetBotChannelsByUser(userID, opts)
if err == nil {
return result, nil
}
if !isRepeatableError(err) {
return result, err
}
tries++
if tries >= 3 {
err = errors.Wrap(err, "giving up after 3 consecutive repeatable transaction failures")
return result, err
}
timepkg.Sleep(100 * timepkg.Millisecond)
}
}
func (s *RetryLayerChannelStore) GetByName(team_id string, name string, allowFromCache bool) (*model.Channel, error) { func (s *RetryLayerChannelStore) GetByName(team_id string, name string, allowFromCache bool) (*model.Channel, error) {
tries := 0 tries := 0
@@ -1948,11 +1969,11 @@ func (s *RetryLayerChannelStore) GetSidebarCategories(userID string, opts *store
} }
func (s *RetryLayerChannelStore) GetSidebarCategoriesForTeamForUser(userID string, teamID string) (*model.OrderedSidebarCategories, error) { func (s *RetryLayerChannelStore) GetSidebarCategoriesForTeamForUser(userID string, teamID string, options ...*store.SidebarCategorySearchOpts) (*model.OrderedSidebarCategories, error) {
tries := 0 tries := 0
for { for {
result, err := s.ChannelStore.GetSidebarCategoriesForTeamForUser(userID, teamID) result, err := s.ChannelStore.GetSidebarCategoriesForTeamForUser(userID, teamID, options...)
if err == nil { if err == nil {
return result, nil return result, nil
} }
@@ -1969,11 +1990,11 @@ func (s *RetryLayerChannelStore) GetSidebarCategoriesForTeamForUser(userID strin
} }
func (s *RetryLayerChannelStore) GetSidebarCategory(categoryID string) (*model.SidebarCategoryWithChannels, error) { func (s *RetryLayerChannelStore) GetSidebarCategory(categoryID string, options ...*store.SidebarCategorySearchOpts) (*model.SidebarCategoryWithChannels, error) {
tries := 0 tries := 0
for { for {
result, err := s.ChannelStore.GetSidebarCategory(categoryID) result, err := s.ChannelStore.GetSidebarCategory(categoryID, options...)
if err == nil { if err == nil {
return result, nil return result, nil
} }
@@ -2878,11 +2899,11 @@ func (s *RetryLayerChannelStore) UpdateMultipleMembers(members []*model.ChannelM
} }
func (s *RetryLayerChannelStore) UpdateSidebarCategories(userID string, teamID string, categories []*model.SidebarCategoryWithChannels) ([]*model.SidebarCategoryWithChannels, []*model.SidebarCategoryWithChannels, error) { func (s *RetryLayerChannelStore) UpdateSidebarCategories(userID string, teamID string, categories []*model.SidebarCategoryWithChannels, options ...*store.SidebarCategorySearchOpts) ([]*model.SidebarCategoryWithChannels, []*model.SidebarCategoryWithChannels, error) {
tries := 0 tries := 0
for { for {
result, resultVar1, err := s.ChannelStore.UpdateSidebarCategories(userID, teamID, categories) result, resultVar1, err := s.ChannelStore.UpdateSidebarCategories(userID, teamID, categories, options...)
if err == nil { if err == nil {
return result, resultVar1, nil return result, resultVar1, nil
} }

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

@@ -1190,6 +1190,38 @@ func (s SqlChannelStore) GetChannelsByUser(userId string, includeDeleted bool, l
return channels, nil return channels, nil
} }
func (s SqlChannelStore) GetBotChannelsByUser(userId string, opts store.ChannelSearchOpts) (model.ChannelList, error) {
query := s.getQueryBuilder().
Select("C.*").
From("Channels as C, ChannelMembers as CM1, ChannelMembers as CM2, Bots as B").
Where(sq.And{
sq.Expr("C.Id = CM1.ChannelId"),
sq.Eq{"CM1.UserId": userId},
sq.Eq{"C.Type": model.ChannelTypeDirect},
sq.Expr("C.Id = CM2.ChannelId"),
sq.Expr("CM2.UserId = B.UserId"),
sq.Eq{"B.DeleteAt": 0},
}).
OrderBy("C.Id ASC")
if !opts.IncludeDeleted {
query = query.Where(sq.Eq{"C.DeleteAt": int(0)})
}
sql, args, err := query.ToSql()
if err != nil {
return nil, errors.Wrap(err, "GetBotChannelsByUser_ToSql")
}
channels := model.ChannelList{}
err = s.GetReplicaX().Select(&channels, sql, args...)
if err != nil {
return nil, errors.Wrapf(err, "failed to get bot channels with UserId=%s", userId)
}
return channels, nil
}
func (s SqlChannelStore) GetAllChannelMembersById(channelID string) ([]string, error) { func (s SqlChannelStore) GetAllChannelMembersById(channelID string) ([]string, error) {
sql, args, err := s.channelMembersForTeamWithSchemeSelectQuery.Where(sq.Eq{ sql, args, err := s.channelMembersForTeamWithSchemeSelectQuery.Where(sq.Eq{
"ChannelId": channelID, "ChannelId": channelID,

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

@@ -58,11 +58,7 @@ func (s SqlChannelStore) createInitialSidebarCategoriesT(transaction *sqlxTxWrap
From("SidebarCategories"). From("SidebarCategories").
Where(sq.Eq{ Where(sq.Eq{
"UserId": userId, "UserId": userId,
"Type": []model.SidebarCategoryType{ "Type": model.SystemSidebarCategories,
model.SidebarCategoryFavorites,
model.SidebarCategoryChannels,
model.SidebarCategoryDirectMessages,
},
}) })
if !opts.ExcludeTeam { if !opts.ExcludeTeam {
@@ -157,6 +153,15 @@ func (s SqlChannelStore) createInitialSidebarCategoriesT(transaction *sqlxTxWrap
hasInsert = true hasInsert = true
} }
if opts.AppsCategoryEnabled {
teamIDs = getRequiredTeamIDs(model.SidebarCategoryApps, opts)
for _, teamID := range teamIDs {
appsCategoryId := fmt.Sprintf("%s_%s_%s", model.SidebarCategoryApps, userId, teamID)
insertBuilder = insertBuilder.Values(appsCategoryId, userId, teamID, model.DefaultSidebarSortOrderApps, model.SidebarCategorySortDefault, model.SidebarCategoryApps, "Apps" /* This will be retranslated by the client into the user's locale */, false, false)
hasInsert = true
}
}
if hasInsert { if hasInsert {
sql, args, err := insertBuilder.ToSql() sql, args, err := insertBuilder.ToSql()
if err != nil { if err != nil {
@@ -296,7 +301,7 @@ type sidebarCategoryForJoin struct {
ChannelId *string ChannelId *string
} }
func (s SqlChannelStore) CreateSidebarCategory(userId, teamId string, newCategory *model.SidebarCategoryWithChannels) (_ *model.SidebarCategoryWithChannels, err error) { func (s SqlChannelStore) CreateSidebarCategory(userId, teamId string, newCategory *model.SidebarCategoryWithChannels, options ...*store.SidebarCategorySearchOpts) (_ *model.SidebarCategoryWithChannels, err error) {
transaction, err := s.GetMasterX().Beginx() transaction, err := s.GetMasterX().Beginx()
if err != nil { if err != nil {
return nil, errors.Wrap(err, "begin_transaction") return nil, errors.Wrap(err, "begin_transaction")
@@ -304,9 +309,15 @@ func (s SqlChannelStore) CreateSidebarCategory(userId, teamId string, newCategor
defer finalizeTransactionX(transaction, &err) defer finalizeTransactionX(transaction, &err)
appsCategoryEnabled := false
if len(options) > 0 {
appsCategoryEnabled = options[0].AppsCategoryEnabled
}
opts := &store.SidebarCategorySearchOpts{ opts := &store.SidebarCategorySearchOpts{
TeamID: teamId, TeamID: teamId,
ExcludeTeam: false, ExcludeTeam: false,
AppsCategoryEnabled: appsCategoryEnabled,
} }
categoriesWithOrder, err := s.getSidebarCategoriesT(transaction, userId, opts) categoriesWithOrder, err := s.getSidebarCategoriesT(transaction, userId, opts)
if err != nil { if err != nil {
@@ -418,14 +429,14 @@ func (s SqlChannelStore) CreateSidebarCategory(userId, teamId string, newCategor
return result, nil return result, nil
} }
func (s SqlChannelStore) completePopulatingCategoryChannels(category *model.SidebarCategoryWithChannels) (_ *model.SidebarCategoryWithChannels, err error) { func (s SqlChannelStore) completePopulatingCategoryChannels(category *model.SidebarCategoryWithChannels, appsCategoryEnabled bool) (_ *model.SidebarCategoryWithChannels, err error) {
transaction, err := s.GetMasterX().Beginx() transaction, err := s.GetMasterX().Beginx()
if err != nil { if err != nil {
return nil, errors.Wrap(err, "begin_transaction") return nil, errors.Wrap(err, "begin_transaction")
} }
defer finalizeTransactionX(transaction, &err) defer finalizeTransactionX(transaction, &err)
result, err := s.completePopulatingCategoryChannelsT(transaction, category) result, err := s.completePopulatingCategoryChannelsT(transaction, category, appsCategoryEnabled)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -437,15 +448,38 @@ func (s SqlChannelStore) completePopulatingCategoryChannels(category *model.Side
return result, nil return result, nil
} }
func (s SqlChannelStore) completePopulatingCategoryChannelsT(db dbSelecter, category *model.SidebarCategoryWithChannels) (*model.SidebarCategoryWithChannels, error) { func (s SqlChannelStore) completePopulatingCategoryChannelsT(db dbSelecter, category *model.SidebarCategoryWithChannels, appsCategoryEnabled bool) (*model.SidebarCategoryWithChannels, error) {
if category.Type == model.SidebarCategoryCustom || category.Type == model.SidebarCategoryFavorites { if category.Type == model.SidebarCategoryCustom || category.Type == model.SidebarCategoryFavorites {
return category, nil return category, nil
} }
var channelTypeFilter sq.Sqlizer var channelTypeFilter sq.Sqlizer
if category.Type == model.SidebarCategoryDirectMessages { if category.Type == model.SidebarCategoryApps || category.Type == model.SidebarCategoryDirectMessages {
// any DM/GM channels that aren't in any category should be returned as part of the Direct Messages category botChannelsIDs := []string{}
channelTypeFilter = sq.Eq{"Channels.Type": []model.ChannelType{model.ChannelTypeDirect, model.ChannelTypeGroup}} if appsCategoryEnabled {
botChannels, err := s.SqlStore.stores.channel.GetBotChannelsByUser(category.UserId, store.ChannelSearchOpts{})
if err != nil {
return nil, err
}
for _, botChannel := range botChannels {
botChannelsIDs = append(botChannelsIDs, botChannel.Id)
}
}
if category.Type == model.SidebarCategoryApps {
// any DM channels with Bots that aren't in any category should be returned as part of the Apps category
channelTypeFilter = sq.And{
sq.Eq{"Channels.Type": model.ChannelTypeDirect},
sq.Eq{"Channels.Id": botChannelsIDs},
}
} else if category.Type == model.SidebarCategoryDirectMessages {
// any DM/GM channels with Users that aren't in any category should be returned as part of the Direct Messages category
channelTypeFilter = sq.And{
sq.Eq{"Channels.Type": []model.ChannelType{model.ChannelTypeDirect, model.ChannelTypeGroup}},
sq.NotEq{"Channels.Id": botChannelsIDs},
}
}
} else if category.Type == model.SidebarCategoryChannels { } else if category.Type == model.SidebarCategoryChannels {
// any public/private channels that are on the current team and aren't in any category should be returned as part of the Channels category // any public/private channels that are on the current team and aren't in any category should be returned as part of the Channels category
channelTypeFilter = sq.And{ channelTypeFilter = sq.And{
@@ -468,6 +502,12 @@ func (s SqlChannelStore) completePopulatingCategoryChannelsT(db dbSelecter, cate
}). }).
Suffix(")") Suffix(")")
if !appsCategoryEnabled {
doesNotHaveSidebarChannel = doesNotHaveSidebarChannel.Where(
sq.NotEq{"SidebarCategories.Type": model.SidebarCategoryApps},
)
}
channels := []string{} channels := []string{}
sql, args, err := s.getQueryBuilder(). sql, args, err := s.getQueryBuilder().
Select("Id"). Select("Id").
@@ -492,7 +532,7 @@ func (s SqlChannelStore) completePopulatingCategoryChannelsT(db dbSelecter, cate
return category, nil return category, nil
} }
func (s SqlChannelStore) GetSidebarCategory(categoryId string) (*model.SidebarCategoryWithChannels, error) { func (s SqlChannelStore) GetSidebarCategory(categoryId string, options ...*store.SidebarCategorySearchOpts) (*model.SidebarCategoryWithChannels, error) {
sql, args, err := s.getQueryBuilder(). sql, args, err := s.getQueryBuilder().
Select("SidebarCategories.*", "SidebarChannels.ChannelId"). Select("SidebarCategories.*", "SidebarChannels.ChannelId").
From("SidebarCategories"). From("SidebarCategories").
@@ -521,7 +561,13 @@ func (s SqlChannelStore) GetSidebarCategory(categoryId string) (*model.SidebarCa
result.Channels = append(result.Channels, *category.ChannelId) result.Channels = append(result.Channels, *category.ChannelId)
} }
} }
return s.completePopulatingCategoryChannels(result)
appsCategoryEnabled := false
if len(options) > 0 {
appsCategoryEnabled = options[0].AppsCategoryEnabled
}
return s.completePopulatingCategoryChannels(result, appsCategoryEnabled)
} }
func (s SqlChannelStore) getSidebarCategoriesT(db dbSelecter, userId string, opts *store.SidebarCategorySearchOpts) (*model.OrderedSidebarCategories, error) { func (s SqlChannelStore) getSidebarCategoriesT(db dbSelecter, userId string, opts *store.SidebarCategorySearchOpts) (*model.OrderedSidebarCategories, error) {
@@ -553,6 +599,10 @@ func (s SqlChannelStore) getSidebarCategoriesT(db dbSelecter, userId string, opt
query = query.Where(sq.Eq{"SidebarCategories.TeamId": opts.TeamID}) query = query.Where(sq.Eq{"SidebarCategories.TeamId": opts.TeamID})
} }
if !opts.AppsCategoryEnabled {
query = query.Where(sq.NotEq{"SidebarCategories.Type": model.SidebarCategoryApps})
}
sql, args, err := query.ToSql() sql, args, err := query.ToSql()
if err != nil { if err != nil {
return nil, errors.Wrap(err, "sidebar_categories_tosql") return nil, errors.Wrap(err, "sidebar_categories_tosql")
@@ -583,7 +633,7 @@ func (s SqlChannelStore) getSidebarCategoriesT(db dbSelecter, userId string, opt
} }
} }
for _, category := range oc.Categories { for _, category := range oc.Categories {
if _, err := s.completePopulatingCategoryChannelsT(db, category); err != nil { if _, err := s.completePopulatingCategoryChannelsT(db, category, opts.AppsCategoryEnabled); err != nil {
return nil, err return nil, err
} }
} }
@@ -591,10 +641,16 @@ func (s SqlChannelStore) getSidebarCategoriesT(db dbSelecter, userId string, opt
return &oc, nil return &oc, nil
} }
func (s SqlChannelStore) GetSidebarCategoriesForTeamForUser(userId, teamId string) (*model.OrderedSidebarCategories, error) { func (s SqlChannelStore) GetSidebarCategoriesForTeamForUser(userId, teamId string, options ...*store.SidebarCategorySearchOpts) (*model.OrderedSidebarCategories, error) {
appsCategoryEnabled := false
if len(options) > 0 {
appsCategoryEnabled = options[0].AppsCategoryEnabled
}
opts := &store.SidebarCategorySearchOpts{ opts := &store.SidebarCategorySearchOpts{
TeamID: teamId, TeamID: teamId,
ExcludeTeam: false, ExcludeTeam: false,
AppsCategoryEnabled: appsCategoryEnabled,
} }
return s.getSidebarCategoriesT(s.GetReplicaX(), userId, opts) return s.getSidebarCategoriesT(s.GetReplicaX(), userId, opts)
} }
@@ -688,17 +744,22 @@ func (s SqlChannelStore) UpdateSidebarCategoryOrder(userId, teamId string, categ
} }
//nolint:unparam //nolint:unparam
func (s SqlChannelStore) UpdateSidebarCategories(userId, teamId string, categories []*model.SidebarCategoryWithChannels) (updated []*model.SidebarCategoryWithChannels, original []*model.SidebarCategoryWithChannels, err error) { func (s SqlChannelStore) UpdateSidebarCategories(userId, teamId string, categories []*model.SidebarCategoryWithChannels, options ...*store.SidebarCategorySearchOpts) (updated []*model.SidebarCategoryWithChannels, original []*model.SidebarCategoryWithChannels, err error) {
transaction, err := s.GetMasterX().Beginx() transaction, err := s.GetMasterX().Beginx()
if err != nil { if err != nil {
return nil, nil, errors.Wrap(err, "begin_transaction") return nil, nil, errors.Wrap(err, "begin_transaction")
} }
defer finalizeTransactionX(transaction, &err) defer finalizeTransactionX(transaction, &err)
opts := &store.SidebarCategorySearchOpts{}
if len(options) > 0 {
opts = options[0]
}
updatedCategories := []*model.SidebarCategoryWithChannels{} updatedCategories := []*model.SidebarCategoryWithChannels{}
originalCategories := []*model.SidebarCategoryWithChannels{} originalCategories := []*model.SidebarCategoryWithChannels{}
for _, category := range categories { for _, category := range categories {
srcCategory, err2 := s.GetSidebarCategory(category.Id) srcCategory, err2 := s.GetSidebarCategory(category.Id, opts)
if err2 != nil { if err2 != nil {
return nil, nil, errors.Wrap(err2, "failed to find SidebarCategories") return nil, nil, errors.Wrap(err2, "failed to find SidebarCategories")
} }
@@ -719,7 +780,7 @@ func (s SqlChannelStore) UpdateSidebarCategories(userId, teamId string, categori
destCategory.DisplayName = srcCategory.DisplayName destCategory.DisplayName = srcCategory.DisplayName
} }
if destCategory.Type != model.SidebarCategoryDirectMessages { if destCategory.Type != model.SidebarCategoryDirectMessages && destCategory.Type != model.SidebarCategoryApps {
destCategory.Channels = make([]string, len(category.Channels)) destCategory.Channels = make([]string, len(category.Channels))
copy(destCategory.Channels, category.Channels) copy(destCategory.Channels, category.Channels)
@@ -746,7 +807,7 @@ func (s SqlChannelStore) UpdateSidebarCategories(userId, teamId string, categori
} }
// if we are updating DM category, it's order can't channel order cannot be changed. // if we are updating DM category, it's order can't channel order cannot be changed.
if category.Type != model.SidebarCategoryDirectMessages { if category.Type != model.SidebarCategoryDirectMessages && destCategory.Type != model.SidebarCategoryApps {
// Remove any SidebarChannels entries that were either: // Remove any SidebarChannels entries that were either:
// - previously in this category (and any ones that are still in the category will be recreated below) // - previously in this category (and any ones that are still in the category will be recreated below)
// - in another category and are being added to this category // - in another category and are being added to this category
@@ -843,7 +904,7 @@ func (s SqlChannelStore) UpdateSidebarCategories(userId, teamId string, categori
// Ensure Channels are populated for Channels/Direct Messages category if they change // Ensure Channels are populated for Channels/Direct Messages category if they change
for i, updatedCategory := range updatedCategories { for i, updatedCategory := range updatedCategories {
populated, nErr := s.completePopulatingCategoryChannelsT(transaction, updatedCategory) populated, nErr := s.completePopulatingCategoryChannelsT(transaction, updatedCategory, opts.AppsCategoryEnabled)
if nErr != nil { if nErr != nil {
return nil, nil, nErr return nil, nil, nErr
} }

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

@@ -11,4 +11,5 @@ import (
func TestChannelStoreCategories(t *testing.T) { func TestChannelStoreCategories(t *testing.T) {
StoreTestWithSqlStore(t, storetest.TestChannelStoreCategories) StoreTestWithSqlStore(t, storetest.TestChannelStoreCategories)
StoreTestWithSqlStore(t, storetest.TestChannelStoreCategoriesWithAppsCategory)
} }

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

@@ -197,6 +197,7 @@ type ChannelStore interface {
GetChannels(teamID, userID string, opts *model.ChannelSearchOpts) (model.ChannelList, error) GetChannels(teamID, userID string, opts *model.ChannelSearchOpts) (model.ChannelList, error)
GetChannelsWithCursor(teamId string, userId string, opts *model.ChannelSearchOpts, afterChannelID string) (model.ChannelList, error) GetChannelsWithCursor(teamId string, userId string, opts *model.ChannelSearchOpts, afterChannelID string) (model.ChannelList, error)
GetChannelsByUser(userID string, includeDeleted bool, lastDeleteAt, pageSize int, fromChannelID string) (model.ChannelList, error) GetChannelsByUser(userID string, includeDeleted bool, lastDeleteAt, pageSize int, fromChannelID string) (model.ChannelList, error)
GetBotChannelsByUser(userID string, opts ChannelSearchOpts) (model.ChannelList, error)
GetAllChannelMembersById(id string) ([]string, error) GetAllChannelMembersById(id string) ([]string, error)
GetAllChannels(page, perPage int, opts ChannelSearchOpts) (model.ChannelListWithTeamData, error) GetAllChannels(page, perPage int, opts ChannelSearchOpts) (model.ChannelListWithTeamData, error)
GetAllChannelsCount(opts ChannelSearchOpts) (int64, error) GetAllChannelsCount(opts ChannelSearchOpts) (int64, error)
@@ -271,13 +272,13 @@ type ChannelStore interface {
ResetAllChannelSchemes() error ResetAllChannelSchemes() error
ClearAllCustomRoleAssignments() error ClearAllCustomRoleAssignments() error
CreateInitialSidebarCategories(userID string, opts *SidebarCategorySearchOpts) (*model.OrderedSidebarCategories, error) CreateInitialSidebarCategories(userID string, opts *SidebarCategorySearchOpts) (*model.OrderedSidebarCategories, error)
GetSidebarCategoriesForTeamForUser(userID, teamID string) (*model.OrderedSidebarCategories, error) GetSidebarCategoriesForTeamForUser(userID, teamID string, options ...*SidebarCategorySearchOpts) (*model.OrderedSidebarCategories, error)
GetSidebarCategories(userID string, opts *SidebarCategorySearchOpts) (*model.OrderedSidebarCategories, error) GetSidebarCategories(userID string, opts *SidebarCategorySearchOpts) (*model.OrderedSidebarCategories, error)
GetSidebarCategory(categoryID string) (*model.SidebarCategoryWithChannels, error) GetSidebarCategory(categoryID string, options ...*SidebarCategorySearchOpts) (*model.SidebarCategoryWithChannels, error)
GetSidebarCategoryOrder(userID, teamID string) ([]string, error) GetSidebarCategoryOrder(userID, teamID string) ([]string, error)
CreateSidebarCategory(userID, teamID string, newCategory *model.SidebarCategoryWithChannels) (*model.SidebarCategoryWithChannels, error) CreateSidebarCategory(userID, teamID string, newCategory *model.SidebarCategoryWithChannels, options ...*SidebarCategorySearchOpts) (*model.SidebarCategoryWithChannels, error)
UpdateSidebarCategoryOrder(userID, teamID string, categoryOrder []string) error UpdateSidebarCategoryOrder(userID, teamID string, categoryOrder []string) error
UpdateSidebarCategories(userID, teamID string, categories []*model.SidebarCategoryWithChannels) ([]*model.SidebarCategoryWithChannels, []*model.SidebarCategoryWithChannels, error) UpdateSidebarCategories(userID, teamID string, categories []*model.SidebarCategoryWithChannels, options ...*SidebarCategorySearchOpts) ([]*model.SidebarCategoryWithChannels, []*model.SidebarCategoryWithChannels, error)
UpdateSidebarChannelsByPreferences(preferences model.Preferences) error UpdateSidebarChannelsByPreferences(preferences model.Preferences) error
DeleteSidebarChannelsByPreferences(preferences model.Preferences) error DeleteSidebarChannelsByPreferences(preferences model.Preferences) error
DeleteSidebarCategory(categoryID string) error DeleteSidebarCategory(categoryID string) error
@@ -1091,8 +1092,9 @@ type PostReminderMetadata struct {
// SidebarCategorySearchOpts contains the options for a graphQL query // SidebarCategorySearchOpts contains the options for a graphQL query
// to get the sidebar categories. // to get the sidebar categories.
type SidebarCategorySearchOpts struct { type SidebarCategorySearchOpts struct {
TeamID string TeamID string
ExcludeTeam bool ExcludeTeam bool
AppsCategoryEnabled bool
} }
// Ensure store service adapter implements `product.StoreService` // Ensure store service adapter implements `product.StoreService`

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@@ -298,25 +298,32 @@ func (_m *ChannelStore) CreateInitialSidebarCategories(userID string, opts *stor
return r0, r1 return r0, r1
} }
// CreateSidebarCategory provides a mock function with given fields: userID, teamID, newCategory // CreateSidebarCategory provides a mock function with given fields: userID, teamID, newCategory, options
func (_m *ChannelStore) CreateSidebarCategory(userID string, teamID string, newCategory *model.SidebarCategoryWithChannels) (*model.SidebarCategoryWithChannels, error) { func (_m *ChannelStore) CreateSidebarCategory(userID string, teamID string, newCategory *model.SidebarCategoryWithChannels, options ...*store.SidebarCategorySearchOpts) (*model.SidebarCategoryWithChannels, error) {
ret := _m.Called(userID, teamID, newCategory) _va := make([]interface{}, len(options))
for _i := range options {
_va[_i] = options[_i]
}
var _ca []interface{}
_ca = append(_ca, userID, teamID, newCategory)
_ca = append(_ca, _va...)
ret := _m.Called(_ca...)
var r0 *model.SidebarCategoryWithChannels var r0 *model.SidebarCategoryWithChannels
var r1 error var r1 error
if rf, ok := ret.Get(0).(func(string, string, *model.SidebarCategoryWithChannels) (*model.SidebarCategoryWithChannels, error)); ok { if rf, ok := ret.Get(0).(func(string, string, *model.SidebarCategoryWithChannels, ...*store.SidebarCategorySearchOpts) (*model.SidebarCategoryWithChannels, error)); ok {
return rf(userID, teamID, newCategory) return rf(userID, teamID, newCategory, options...)
} }
if rf, ok := ret.Get(0).(func(string, string, *model.SidebarCategoryWithChannels) *model.SidebarCategoryWithChannels); ok { if rf, ok := ret.Get(0).(func(string, string, *model.SidebarCategoryWithChannels, ...*store.SidebarCategorySearchOpts) *model.SidebarCategoryWithChannels); ok {
r0 = rf(userID, teamID, newCategory) r0 = rf(userID, teamID, newCategory, options...)
} else { } else {
if ret.Get(0) != nil { if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.SidebarCategoryWithChannels) r0 = ret.Get(0).(*model.SidebarCategoryWithChannels)
} }
} }
if rf, ok := ret.Get(1).(func(string, string, *model.SidebarCategoryWithChannels) error); ok { if rf, ok := ret.Get(1).(func(string, string, *model.SidebarCategoryWithChannels, ...*store.SidebarCategorySearchOpts) error); ok {
r1 = rf(userID, teamID, newCategory) r1 = rf(userID, teamID, newCategory, options...)
} else { } else {
r1 = ret.Error(1) r1 = ret.Error(1)
} }
@@ -598,6 +605,32 @@ func (_m *ChannelStore) GetAllDirectChannelsForExportAfter(limit int, afterID st
return r0, r1 return r0, r1
} }
// GetBotChannelsByUser provides a mock function with given fields: userID, opts
func (_m *ChannelStore) GetBotChannelsByUser(userID string, opts store.ChannelSearchOpts) (model.ChannelList, error) {
ret := _m.Called(userID, opts)
var r0 model.ChannelList
var r1 error
if rf, ok := ret.Get(0).(func(string, store.ChannelSearchOpts) (model.ChannelList, error)); ok {
return rf(userID, opts)
}
if rf, ok := ret.Get(0).(func(string, store.ChannelSearchOpts) model.ChannelList); ok {
r0 = rf(userID, opts)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(model.ChannelList)
}
}
if rf, ok := ret.Get(1).(func(string, store.ChannelSearchOpts) error); ok {
r1 = rf(userID, opts)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// GetByName provides a mock function with given fields: team_id, name, allowFromCache // GetByName provides a mock function with given fields: team_id, name, allowFromCache
func (_m *ChannelStore) GetByName(team_id string, name string, allowFromCache bool) (*model.Channel, error) { func (_m *ChannelStore) GetByName(team_id string, name string, allowFromCache bool) (*model.Channel, error) {
ret := _m.Called(team_id, name, allowFromCache) ret := _m.Called(team_id, name, allowFromCache)
@@ -1592,25 +1625,32 @@ func (_m *ChannelStore) GetSidebarCategories(userID string, opts *store.SidebarC
return r0, r1 return r0, r1
} }
// GetSidebarCategoriesForTeamForUser provides a mock function with given fields: userID, teamID // GetSidebarCategoriesForTeamForUser provides a mock function with given fields: userID, teamID, options
func (_m *ChannelStore) GetSidebarCategoriesForTeamForUser(userID string, teamID string) (*model.OrderedSidebarCategories, error) { func (_m *ChannelStore) GetSidebarCategoriesForTeamForUser(userID string, teamID string, options ...*store.SidebarCategorySearchOpts) (*model.OrderedSidebarCategories, error) {
ret := _m.Called(userID, teamID) _va := make([]interface{}, len(options))
for _i := range options {
_va[_i] = options[_i]
}
var _ca []interface{}
_ca = append(_ca, userID, teamID)
_ca = append(_ca, _va...)
ret := _m.Called(_ca...)
var r0 *model.OrderedSidebarCategories var r0 *model.OrderedSidebarCategories
var r1 error var r1 error
if rf, ok := ret.Get(0).(func(string, string) (*model.OrderedSidebarCategories, error)); ok { if rf, ok := ret.Get(0).(func(string, string, ...*store.SidebarCategorySearchOpts) (*model.OrderedSidebarCategories, error)); ok {
return rf(userID, teamID) return rf(userID, teamID, options...)
} }
if rf, ok := ret.Get(0).(func(string, string) *model.OrderedSidebarCategories); ok { if rf, ok := ret.Get(0).(func(string, string, ...*store.SidebarCategorySearchOpts) *model.OrderedSidebarCategories); ok {
r0 = rf(userID, teamID) r0 = rf(userID, teamID, options...)
} else { } else {
if ret.Get(0) != nil { if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.OrderedSidebarCategories) r0 = ret.Get(0).(*model.OrderedSidebarCategories)
} }
} }
if rf, ok := ret.Get(1).(func(string, string) error); ok { if rf, ok := ret.Get(1).(func(string, string, ...*store.SidebarCategorySearchOpts) error); ok {
r1 = rf(userID, teamID) r1 = rf(userID, teamID, options...)
} else { } else {
r1 = ret.Error(1) r1 = ret.Error(1)
} }
@@ -1618,25 +1658,32 @@ func (_m *ChannelStore) GetSidebarCategoriesForTeamForUser(userID string, teamID
return r0, r1 return r0, r1
} }
// GetSidebarCategory provides a mock function with given fields: categoryID // GetSidebarCategory provides a mock function with given fields: categoryID, options
func (_m *ChannelStore) GetSidebarCategory(categoryID string) (*model.SidebarCategoryWithChannels, error) { func (_m *ChannelStore) GetSidebarCategory(categoryID string, options ...*store.SidebarCategorySearchOpts) (*model.SidebarCategoryWithChannels, error) {
ret := _m.Called(categoryID) _va := make([]interface{}, len(options))
for _i := range options {
_va[_i] = options[_i]
}
var _ca []interface{}
_ca = append(_ca, categoryID)
_ca = append(_ca, _va...)
ret := _m.Called(_ca...)
var r0 *model.SidebarCategoryWithChannels var r0 *model.SidebarCategoryWithChannels
var r1 error var r1 error
if rf, ok := ret.Get(0).(func(string) (*model.SidebarCategoryWithChannels, error)); ok { if rf, ok := ret.Get(0).(func(string, ...*store.SidebarCategorySearchOpts) (*model.SidebarCategoryWithChannels, error)); ok {
return rf(categoryID) return rf(categoryID, options...)
} }
if rf, ok := ret.Get(0).(func(string) *model.SidebarCategoryWithChannels); ok { if rf, ok := ret.Get(0).(func(string, ...*store.SidebarCategorySearchOpts) *model.SidebarCategoryWithChannels); ok {
r0 = rf(categoryID) r0 = rf(categoryID, options...)
} else { } else {
if ret.Get(0) != nil { if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.SidebarCategoryWithChannels) r0 = ret.Get(0).(*model.SidebarCategoryWithChannels)
} }
} }
if rf, ok := ret.Get(1).(func(string) error); ok { if rf, ok := ret.Get(1).(func(string, ...*store.SidebarCategorySearchOpts) error); ok {
r1 = rf(categoryID) r1 = rf(categoryID, options...)
} else { } else {
r1 = ret.Error(1) r1 = ret.Error(1)
} }
@@ -2582,34 +2629,41 @@ func (_m *ChannelStore) UpdateMultipleMembers(members []*model.ChannelMember) ([
return r0, r1 return r0, r1
} }
// UpdateSidebarCategories provides a mock function with given fields: userID, teamID, categories // UpdateSidebarCategories provides a mock function with given fields: userID, teamID, categories, options
func (_m *ChannelStore) UpdateSidebarCategories(userID string, teamID string, categories []*model.SidebarCategoryWithChannels) ([]*model.SidebarCategoryWithChannels, []*model.SidebarCategoryWithChannels, error) { func (_m *ChannelStore) UpdateSidebarCategories(userID string, teamID string, categories []*model.SidebarCategoryWithChannels, options ...*store.SidebarCategorySearchOpts) ([]*model.SidebarCategoryWithChannels, []*model.SidebarCategoryWithChannels, error) {
ret := _m.Called(userID, teamID, categories) _va := make([]interface{}, len(options))
for _i := range options {
_va[_i] = options[_i]
}
var _ca []interface{}
_ca = append(_ca, userID, teamID, categories)
_ca = append(_ca, _va...)
ret := _m.Called(_ca...)
var r0 []*model.SidebarCategoryWithChannels var r0 []*model.SidebarCategoryWithChannels
var r1 []*model.SidebarCategoryWithChannels var r1 []*model.SidebarCategoryWithChannels
var r2 error var r2 error
if rf, ok := ret.Get(0).(func(string, string, []*model.SidebarCategoryWithChannels) ([]*model.SidebarCategoryWithChannels, []*model.SidebarCategoryWithChannels, error)); ok { if rf, ok := ret.Get(0).(func(string, string, []*model.SidebarCategoryWithChannels, ...*store.SidebarCategorySearchOpts) ([]*model.SidebarCategoryWithChannels, []*model.SidebarCategoryWithChannels, error)); ok {
return rf(userID, teamID, categories) return rf(userID, teamID, categories, options...)
} }
if rf, ok := ret.Get(0).(func(string, string, []*model.SidebarCategoryWithChannels) []*model.SidebarCategoryWithChannels); ok { if rf, ok := ret.Get(0).(func(string, string, []*model.SidebarCategoryWithChannels, ...*store.SidebarCategorySearchOpts) []*model.SidebarCategoryWithChannels); ok {
r0 = rf(userID, teamID, categories) r0 = rf(userID, teamID, categories, options...)
} else { } else {
if ret.Get(0) != nil { if ret.Get(0) != nil {
r0 = ret.Get(0).([]*model.SidebarCategoryWithChannels) r0 = ret.Get(0).([]*model.SidebarCategoryWithChannels)
} }
} }
if rf, ok := ret.Get(1).(func(string, string, []*model.SidebarCategoryWithChannels) []*model.SidebarCategoryWithChannels); ok { if rf, ok := ret.Get(1).(func(string, string, []*model.SidebarCategoryWithChannels, ...*store.SidebarCategorySearchOpts) []*model.SidebarCategoryWithChannels); ok {
r1 = rf(userID, teamID, categories) r1 = rf(userID, teamID, categories, options...)
} else { } else {
if ret.Get(1) != nil { if ret.Get(1) != nil {
r1 = ret.Get(1).([]*model.SidebarCategoryWithChannels) r1 = ret.Get(1).([]*model.SidebarCategoryWithChannels)
} }
} }
if rf, ok := ret.Get(2).(func(string, string, []*model.SidebarCategoryWithChannels) error); ok { if rf, ok := ret.Get(2).(func(string, string, []*model.SidebarCategoryWithChannels, ...*store.SidebarCategorySearchOpts) error); ok {
r2 = rf(userID, teamID, categories) r2 = rf(userID, teamID, categories, options...)
} else { } else {
r2 = ret.Error(2) r2 = ret.Error(2)
} }

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

@@ -774,10 +774,10 @@ func (s *TimerLayerChannelStore) CreateInitialSidebarCategories(userID string, o
return result, err return result, err
} }
func (s *TimerLayerChannelStore) CreateSidebarCategory(userID string, teamID string, newCategory *model.SidebarCategoryWithChannels) (*model.SidebarCategoryWithChannels, error) { func (s *TimerLayerChannelStore) CreateSidebarCategory(userID string, teamID string, newCategory *model.SidebarCategoryWithChannels, options ...*store.SidebarCategorySearchOpts) (*model.SidebarCategoryWithChannels, error) {
start := time.Now() start := time.Now()
result, err := s.ChannelStore.CreateSidebarCategory(userID, teamID, newCategory) result, err := s.ChannelStore.CreateSidebarCategory(userID, teamID, newCategory, options...)
elapsed := float64(time.Since(start)) / float64(time.Second) elapsed := float64(time.Since(start)) / float64(time.Second)
if s.Root.Metrics != nil { if s.Root.Metrics != nil {
@@ -982,6 +982,22 @@ func (s *TimerLayerChannelStore) GetAllDirectChannelsForExportAfter(limit int, a
return result, err return result, err
} }
func (s *TimerLayerChannelStore) GetBotChannelsByUser(userID string, opts store.ChannelSearchOpts) (model.ChannelList, error) {
start := time.Now()
result, err := s.ChannelStore.GetBotChannelsByUser(userID, opts)
elapsed := float64(time.Since(start)) / float64(time.Second)
if s.Root.Metrics != nil {
success := "false"
if err == nil {
success = "true"
}
s.Root.Metrics.ObserveStoreMethodDuration("ChannelStore.GetBotChannelsByUser", success, elapsed)
}
return result, err
}
func (s *TimerLayerChannelStore) GetByName(team_id string, name string, allowFromCache bool) (*model.Channel, error) { func (s *TimerLayerChannelStore) GetByName(team_id string, name string, allowFromCache bool) (*model.Channel, error) {
start := time.Now() start := time.Now()
@@ -1606,10 +1622,10 @@ func (s *TimerLayerChannelStore) GetSidebarCategories(userID string, opts *store
return result, err return result, err
} }
func (s *TimerLayerChannelStore) GetSidebarCategoriesForTeamForUser(userID string, teamID string) (*model.OrderedSidebarCategories, error) { func (s *TimerLayerChannelStore) GetSidebarCategoriesForTeamForUser(userID string, teamID string, options ...*store.SidebarCategorySearchOpts) (*model.OrderedSidebarCategories, error) {
start := time.Now() start := time.Now()
result, err := s.ChannelStore.GetSidebarCategoriesForTeamForUser(userID, teamID) result, err := s.ChannelStore.GetSidebarCategoriesForTeamForUser(userID, teamID, options...)
elapsed := float64(time.Since(start)) / float64(time.Second) elapsed := float64(time.Since(start)) / float64(time.Second)
if s.Root.Metrics != nil { if s.Root.Metrics != nil {
@@ -1622,10 +1638,10 @@ func (s *TimerLayerChannelStore) GetSidebarCategoriesForTeamForUser(userID strin
return result, err return result, err
} }
func (s *TimerLayerChannelStore) GetSidebarCategory(categoryID string) (*model.SidebarCategoryWithChannels, error) { func (s *TimerLayerChannelStore) GetSidebarCategory(categoryID string, options ...*store.SidebarCategorySearchOpts) (*model.SidebarCategoryWithChannels, error) {
start := time.Now() start := time.Now()
result, err := s.ChannelStore.GetSidebarCategory(categoryID) result, err := s.ChannelStore.GetSidebarCategory(categoryID, options...)
elapsed := float64(time.Since(start)) / float64(time.Second) elapsed := float64(time.Since(start)) / float64(time.Second)
if s.Root.Metrics != nil { if s.Root.Metrics != nil {
@@ -2399,10 +2415,10 @@ func (s *TimerLayerChannelStore) UpdateMultipleMembers(members []*model.ChannelM
return result, err return result, err
} }
func (s *TimerLayerChannelStore) UpdateSidebarCategories(userID string, teamID string, categories []*model.SidebarCategoryWithChannels) ([]*model.SidebarCategoryWithChannels, []*model.SidebarCategoryWithChannels, error) { func (s *TimerLayerChannelStore) UpdateSidebarCategories(userID string, teamID string, categories []*model.SidebarCategoryWithChannels, options ...*store.SidebarCategorySearchOpts) ([]*model.SidebarCategoryWithChannels, []*model.SidebarCategoryWithChannels, error) {
start := time.Now() start := time.Now()
result, resultVar1, err := s.ChannelStore.UpdateSidebarCategories(userID, teamID, categories) result, resultVar1, err := s.ChannelStore.UpdateSidebarCategories(userID, teamID, categories, options...)
elapsed := float64(time.Since(start)) / float64(time.Second) elapsed := float64(time.Since(start)) / float64(time.Second)
if s.Root.Metrics != nil { if s.Root.Metrics != nil {

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

@@ -13,11 +13,12 @@ type SidebarCategoryType string
type SidebarCategorySorting string type SidebarCategorySorting string
const ( const (
// Each sidebar category has a 'type'. System categories are Channels, Favorites and DMs // Each sidebar category has a 'type'. System categories are Channels, Favorites, DMs and Apps
// All user-created categories will have type Custom // All user-created categories will have type Custom
SidebarCategoryChannels SidebarCategoryType = "channels" SidebarCategoryChannels SidebarCategoryType = "channels"
SidebarCategoryDirectMessages SidebarCategoryType = "direct_messages" SidebarCategoryDirectMessages SidebarCategoryType = "direct_messages"
SidebarCategoryFavorites SidebarCategoryType = "favorites" SidebarCategoryFavorites SidebarCategoryType = "favorites"
SidebarCategoryApps SidebarCategoryType = "apps"
SidebarCategoryCustom SidebarCategoryType = "custom" SidebarCategoryCustom SidebarCategoryType = "custom"
// Increment to use when adding/reordering things in the sidebar // Increment to use when adding/reordering things in the sidebar
MinimalSidebarSortDistance = 10 MinimalSidebarSortDistance = 10
@@ -25,6 +26,7 @@ const (
DefaultSidebarSortOrderFavorites = 0 DefaultSidebarSortOrderFavorites = 0
DefaultSidebarSortOrderChannels = DefaultSidebarSortOrderFavorites + MinimalSidebarSortDistance DefaultSidebarSortOrderChannels = DefaultSidebarSortOrderFavorites + MinimalSidebarSortDistance
DefaultSidebarSortOrderDMs = DefaultSidebarSortOrderChannels + MinimalSidebarSortDistance DefaultSidebarSortOrderDMs = DefaultSidebarSortOrderChannels + MinimalSidebarSortDistance
DefaultSidebarSortOrderApps = DefaultSidebarSortOrderDMs + MinimalSidebarSortDistance
// Sorting modes // Sorting modes
// default for all categories except DMs (behaves like manual) // default for all categories except DMs (behaves like manual)
SidebarCategorySortDefault SidebarCategorySorting = "" SidebarCategorySortDefault SidebarCategorySorting = ""
@@ -36,6 +38,13 @@ const (
SidebarCategorySortAlphabetical SidebarCategorySorting = "alpha" SidebarCategorySortAlphabetical SidebarCategorySorting = "alpha"
) )
var SystemSidebarCategories = []SidebarCategoryType{
SidebarCategoryChannels,
SidebarCategoryDirectMessages,
SidebarCategoryFavorites,
SidebarCategoryApps,
}
// SidebarCategory represents the corresponding DB table // SidebarCategory represents the corresponding DB table
type SidebarCategory struct { type SidebarCategory struct {
Id string `json:"id"` Id string `json:"id"`
@@ -77,7 +86,7 @@ type SidebarChannel struct {
type SidebarChannels []*SidebarChannel type SidebarChannels []*SidebarChannel
type SidebarCategoriesWithChannels []*SidebarCategoryWithChannels type SidebarCategoriesWithChannels []*SidebarCategoryWithChannels
var categoryIdPattern = regexp.MustCompile("(favorites|channels|direct_messages)_[a-z0-9]{26}_[a-z0-9]{26}") var categoryIdPattern = regexp.MustCompile("(favorites|channels|direct_messages|apps)_[a-z0-9]{26}_[a-z0-9]{26}")
func IsValidCategoryId(s string) bool { func IsValidCategoryId(s string) bool {
// Category IDs can either be regular IDs // Category IDs can either be regular IDs