From 6a5bb539633ecdb68d4bd3f7e979a6dac5c3251f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Andr=C3=A9s=20V=C3=A9lez=20Vidal?= Date: Wed, 14 Jun 2023 11:05:21 +0200 Subject: [PATCH] [MM-52969] Revert "MM-51482_Create Apps Category and link to bots DM (#22918)" (#23647) * Revert "MM-51482_Create Apps Category and link to bots DM (#22918)" This reverts commit 1051925eecd3a20dada79137e539716bb9994187. * Revert "MM-51711_Feature flag: APPS sidebar category (#22766)" This reverts commit 9156205178606dc02f966db7efde0a749939848d. --- .../support/server/default_config.ts | 1 - server/channels/api4/resolver.go | 7 +- server/channels/app/channel_category.go | 61 +- ...hannel_category_with_apps_category_test.go | 481 --- server/channels/app/helper_test.go | 6 - server/channels/app/team.go | 6 +- server/channels/app/team_test.go | 113 - .../channels/store/layer_generators/main.go | 4 - .../opentracinglayer/opentracinglayer.go | 34 +- .../channels/store/retrylayer/retrylayer.go | 37 +- .../channels/store/sqlstore/channel_store.go | 32 - .../sqlstore/channel_store_categories.go | 111 +- .../sqlstore/channel_store_categories_test.go | 1 - server/channels/store/store.go | 14 +- ...nel_store_categories_with_apps_category.go | 2681 ----------------- .../store/storetest/mocks/ChannelStore.go | 130 +- .../channels/store/timerlayer/timerlayer.go | 32 +- server/public/model/channel_sidebar.go | 13 +- server/public/model/feature_flags.go | 3 - .../selectors/entities/preferences.test.ts | 38 - .../src/selectors/entities/preferences.ts | 4 - webapp/platform/types/src/config.ts | 1 - 22 files changed, 113 insertions(+), 3697 deletions(-) delete mode 100644 server/channels/app/channel_category_with_apps_category_test.go delete mode 100644 server/channels/store/storetest/channel_store_categories_with_apps_category.go diff --git a/e2e-tests/playwright/support/server/default_config.ts b/e2e-tests/playwright/support/server/default_config.ts index 0ffcdac005..8bb831bd47 100644 --- a/e2e-tests/playwright/support/server/default_config.ts +++ b/e2e-tests/playwright/support/server/default_config.ts @@ -680,7 +680,6 @@ const defaultServerConfig: AdminConfig = { GlobalDrafts: true, OnboardingTourTips: true, DeprecateCloudFree: false, - AppsSidebarCategory: false, CloudReverseTrial: false, }, ImportSettings: { diff --git a/server/channels/api4/resolver.go b/server/channels/api4/resolver.go index 942e3f4349..ce100f4647 100644 --- a/server/channels/api4/resolver.go +++ b/server/channels/api4/resolver.go @@ -353,12 +353,9 @@ func (*resolver) SidebarCategories(ctx context.Context, args struct { return nil, appErr } } else { - appsCategoryEnabled := c.App.Config().FeatureFlags.AppsSidebarCategory - opts := &store.SidebarCategorySearchOpts{ - TeamID: args.TeamID, - ExcludeTeam: args.ExcludeTeam, - AppsCategoryEnabled: appsCategoryEnabled, + TeamID: args.TeamID, + ExcludeTeam: args.ExcludeTeam, } categories, appErr = c.App.GetSidebarCategories(c.AppContext, args.UserID, opts) if appErr != nil { diff --git a/server/channels/app/channel_category.go b/server/channels/app/channel_category.go index cfa2735f8c..7043abe627 100644 --- a/server/channels/app/channel_category.go +++ b/server/channels/app/channel_category.go @@ -25,17 +25,13 @@ func (a *App) createInitialSidebarCategories(userID string, opts *store.SidebarC func (a *App) GetSidebarCategoriesForTeamForUser(c request.CTX, userID, teamID string) (*model.OrderedSidebarCategories, *model.AppError) { var appErr *model.AppError - appsCategoryEnabled := a.Config().FeatureFlags.AppsSidebarCategory - options := &store.SidebarCategorySearchOpts{ - TeamID: teamID, - ExcludeTeam: false, - AppsCategoryEnabled: appsCategoryEnabled, - } - 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) - + categories, err := a.Srv().Store().Channel().GetSidebarCategoriesForTeamForUser(userID, teamID) + if err == nil && len(categories.Categories) == 0 { + // A user must always have categories, so migration must not have happened yet, and we should run it ourselves + categories, appErr = a.createInitialSidebarCategories(userID, &store.SidebarCategorySearchOpts{ + TeamID: teamID, + ExcludeTeam: false, + }) if appErr != nil { return nil, appErr } @@ -56,17 +52,10 @@ 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) { var appErr *model.AppError - appsCategoryEnabled := a.Config().FeatureFlags.AppsSidebarCategory - options := &store.SidebarCategorySearchOpts{ - TeamID: opts.TeamID, - 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) - + categories, err := a.Srv().Store().Channel().GetSidebarCategories(userID, opts) + if err == nil && len(categories.Categories) == 0 { + // A user must always have categories, so migration must not have happened yet, and we should run it ourselves + categories, appErr = a.createInitialSidebarCategories(userID, opts) if appErr != nil { return nil, appErr } @@ -101,8 +90,7 @@ func (a *App) GetSidebarCategoryOrder(c request.CTX, userID, teamID string) ([]s } func (a *App) GetSidebarCategory(c request.CTX, categoryId string) (*model.SidebarCategoryWithChannels, *model.AppError) { - appsCategoryEnabled := a.Config().FeatureFlags.AppsSidebarCategory - category, err := a.Srv().Store().Channel().GetSidebarCategory(categoryId, &store.SidebarCategorySearchOpts{AppsCategoryEnabled: appsCategoryEnabled}) + category, err := a.Srv().Store().Channel().GetSidebarCategory(categoryId) if err != nil { var nfErr *store.ErrNotFound switch { @@ -117,8 +105,7 @@ 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) { - appsCategoryEnabled := a.Config().FeatureFlags.AppsSidebarCategory - category, err := a.Srv().Store().Channel().CreateSidebarCategory(userID, teamID, newCategory, &store.SidebarCategorySearchOpts{AppsCategoryEnabled: appsCategoryEnabled}) + category, err := a.Srv().Store().Channel().CreateSidebarCategory(userID, teamID, newCategory) if err != nil { var nfErr *store.ErrNotFound switch { @@ -155,13 +142,7 @@ 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) { - appsCategoryEnabled := a.Config().FeatureFlags.AppsSidebarCategory - updatedCategories, originalCategories, err := a.Srv().Store().Channel().UpdateSidebarCategories( - userID, - teamID, - categories, - &store.SidebarCategorySearchOpts{AppsCategoryEnabled: appsCategoryEnabled}, - ) + updatedCategories, originalCategories, err := a.Srv().Store().Channel().UpdateSidebarCategories(userID, teamID, categories) if err != nil { return nil, model.NewAppError("UpdateSidebarCategories", "app.channel.sidebar_categories.app_error", nil, "", http.StatusInternalServerError).Wrap(err) } @@ -305,17 +286,3 @@ func (a *App) DeleteSidebarCategory(c request.CTX, userID, teamID, categoryId st 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 -} diff --git a/server/channels/app/channel_category_with_apps_category_test.go b/server/channels/app/channel_category_with_apps_category_test.go deleted file mode 100644 index d9b7609d1f..0000000000 --- a/server/channels/app/channel_category_with_apps_category_test.go +++ /dev/null @@ -1,481 +0,0 @@ -// 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/public/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()) - }) -} diff --git a/server/channels/app/helper_test.go b/server/channels/app/helper_test.go index acb8d42851..5d05c7e610 100644 --- a/server/channels/app/helper_test.go +++ b/server/channels/app/helper_test.go @@ -253,12 +253,6 @@ func (th *TestHelper) InitBasic() *TestHelper { return th } -func (th *TestHelper) InitBasicWithAppsSidebarEnabled() *TestHelper { - th.App.Config().FeatureFlags.AppsSidebarCategory = true - - return th.InitBasic() -} - func (th *TestHelper) DeleteBots() *TestHelper { preexistingBots, _ := th.App.GetBots(&model.BotGetOptions{Page: 0, PerPage: 100}) for _, bot := range preexistingBots { diff --git a/server/channels/app/team.go b/server/channels/app/team.go index af9bc08c9f..c1940208f1 100644 --- a/server/channels/app/team.go +++ b/server/channels/app/team.go @@ -956,11 +956,9 @@ 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) } - appsCategoryEnabled := a.Config().FeatureFlags.AppsSidebarCategory opts := &store.SidebarCategorySearchOpts{ - TeamID: team.Id, - ExcludeTeam: false, - AppsCategoryEnabled: appsCategoryEnabled, + TeamID: team.Id, + ExcludeTeam: false, } if _, err := a.createInitialSidebarCategories(user.Id, opts); err != nil { mlog.Warn( diff --git a/server/channels/app/team_test.go b/server/channels/app/team_test.go index ba91847e27..232a28acb4 100644 --- a/server/channels/app/team_test.go +++ b/server/channels/app/team_test.go @@ -1025,119 +1025,6 @@ 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) { th := SetupWithStoreMock(t) defer th.TearDown() diff --git a/server/channels/store/layer_generators/main.go b/server/channels/store/layer_generators/main.go index a1dac2b667..cfb95abdb8 100644 --- a/server/channels/store/layer_generators/main.go +++ b/server/channels/store/layer_generators/main.go @@ -296,8 +296,6 @@ func generateLayer(name, templateFile string) ([]byte, error) { paramsWithType = append(paramsWithType, fmt.Sprintf("%s store.%s", param.Name, param.Type)) case "*UserGetByIdsOpts", "*ChannelMemberGraphQLSearchOpts", "*SidebarCategorySearchOpts": 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: paramsWithType = append(paramsWithType, fmt.Sprintf("%s %s", param.Name, param.Type)) } @@ -312,8 +310,6 @@ func generateLayer(name, templateFile string) ([]byte, error) { paramsWithType = append(paramsWithType, fmt.Sprintf("%s store.%s", param.Name, param.Type)) case "*UserGetByIdsOpts", "*ChannelMemberGraphQLSearchOpts", "*SidebarCategorySearchOpts": 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: paramsWithType = append(paramsWithType, fmt.Sprintf("%s %s", param.Name, param.Type)) } diff --git a/server/channels/store/opentracinglayer/opentracinglayer.go b/server/channels/store/opentracinglayer/opentracinglayer.go index a2e911d5f6..3e2808afab 100644 --- a/server/channels/store/opentracinglayer/opentracinglayer.go +++ b/server/channels/store/opentracinglayer/opentracinglayer.go @@ -819,7 +819,7 @@ func (s *OpenTracingLayerChannelStore) CreateInitialSidebarCategories(userID str return result, err } -func (s *OpenTracingLayerChannelStore) CreateSidebarCategory(userID string, teamID string, newCategory *model.SidebarCategoryWithChannels, options ...*store.SidebarCategorySearchOpts) (*model.SidebarCategoryWithChannels, error) { +func (s *OpenTracingLayerChannelStore) CreateSidebarCategory(userID string, teamID string, newCategory *model.SidebarCategoryWithChannels) (*model.SidebarCategoryWithChannels, error) { origCtx := s.Root.Store.Context() span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.CreateSidebarCategory") s.Root.Store.SetContext(newCtx) @@ -828,7 +828,7 @@ func (s *OpenTracingLayerChannelStore) CreateSidebarCategory(userID string, team }() defer span.Finish() - result, err := s.ChannelStore.CreateSidebarCategory(userID, teamID, newCategory, options...) + result, err := s.ChannelStore.CreateSidebarCategory(userID, teamID, newCategory) if err != nil { span.LogFields(spanlog.Error(err)) ext.Error.Set(span, true) @@ -1053,24 +1053,6 @@ func (s *OpenTracingLayerChannelStore) GetAllDirectChannelsForExportAfter(limit 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) { origCtx := s.Root.Store.Context() span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.GetByName") @@ -1768,7 +1750,7 @@ func (s *OpenTracingLayerChannelStore) GetSidebarCategories(userID string, opts return result, err } -func (s *OpenTracingLayerChannelStore) GetSidebarCategoriesForTeamForUser(userID string, teamID string, options ...*store.SidebarCategorySearchOpts) (*model.OrderedSidebarCategories, error) { +func (s *OpenTracingLayerChannelStore) GetSidebarCategoriesForTeamForUser(userID string, teamID string) (*model.OrderedSidebarCategories, error) { origCtx := s.Root.Store.Context() span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.GetSidebarCategoriesForTeamForUser") s.Root.Store.SetContext(newCtx) @@ -1777,7 +1759,7 @@ func (s *OpenTracingLayerChannelStore) GetSidebarCategoriesForTeamForUser(userID }() defer span.Finish() - result, err := s.ChannelStore.GetSidebarCategoriesForTeamForUser(userID, teamID, options...) + result, err := s.ChannelStore.GetSidebarCategoriesForTeamForUser(userID, teamID) if err != nil { span.LogFields(spanlog.Error(err)) ext.Error.Set(span, true) @@ -1786,7 +1768,7 @@ func (s *OpenTracingLayerChannelStore) GetSidebarCategoriesForTeamForUser(userID return result, err } -func (s *OpenTracingLayerChannelStore) GetSidebarCategory(categoryID string, options ...*store.SidebarCategorySearchOpts) (*model.SidebarCategoryWithChannels, error) { +func (s *OpenTracingLayerChannelStore) GetSidebarCategory(categoryID string) (*model.SidebarCategoryWithChannels, error) { origCtx := s.Root.Store.Context() span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.GetSidebarCategory") s.Root.Store.SetContext(newCtx) @@ -1795,7 +1777,7 @@ func (s *OpenTracingLayerChannelStore) GetSidebarCategory(categoryID string, opt }() defer span.Finish() - result, err := s.ChannelStore.GetSidebarCategory(categoryID, options...) + result, err := s.ChannelStore.GetSidebarCategory(categoryID) if err != nil { span.LogFields(spanlog.Error(err)) ext.Error.Set(span, true) @@ -2628,7 +2610,7 @@ func (s *OpenTracingLayerChannelStore) UpdateMultipleMembers(members []*model.Ch return result, err } -func (s *OpenTracingLayerChannelStore) UpdateSidebarCategories(userID string, teamID string, categories []*model.SidebarCategoryWithChannels, options ...*store.SidebarCategorySearchOpts) ([]*model.SidebarCategoryWithChannels, []*model.SidebarCategoryWithChannels, error) { +func (s *OpenTracingLayerChannelStore) UpdateSidebarCategories(userID string, teamID string, categories []*model.SidebarCategoryWithChannels) ([]*model.SidebarCategoryWithChannels, []*model.SidebarCategoryWithChannels, error) { origCtx := s.Root.Store.Context() span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.UpdateSidebarCategories") s.Root.Store.SetContext(newCtx) @@ -2637,7 +2619,7 @@ func (s *OpenTracingLayerChannelStore) UpdateSidebarCategories(userID string, te }() defer span.Finish() - result, resultVar1, err := s.ChannelStore.UpdateSidebarCategories(userID, teamID, categories, options...) + result, resultVar1, err := s.ChannelStore.UpdateSidebarCategories(userID, teamID, categories) if err != nil { span.LogFields(spanlog.Error(err)) ext.Error.Set(span, true) diff --git a/server/channels/store/retrylayer/retrylayer.go b/server/channels/store/retrylayer/retrylayer.go index e39ff6dc79..1222cfbfc5 100644 --- a/server/channels/store/retrylayer/retrylayer.go +++ b/server/channels/store/retrylayer/retrylayer.go @@ -881,11 +881,11 @@ func (s *RetryLayerChannelStore) CreateInitialSidebarCategories(userID string, o } -func (s *RetryLayerChannelStore) CreateSidebarCategory(userID string, teamID string, newCategory *model.SidebarCategoryWithChannels, options ...*store.SidebarCategorySearchOpts) (*model.SidebarCategoryWithChannels, error) { +func (s *RetryLayerChannelStore) CreateSidebarCategory(userID string, teamID string, newCategory *model.SidebarCategoryWithChannels) (*model.SidebarCategoryWithChannels, error) { tries := 0 for { - result, err := s.ChannelStore.CreateSidebarCategory(userID, teamID, newCategory, options...) + result, err := s.ChannelStore.CreateSidebarCategory(userID, teamID, newCategory) if err == nil { return result, nil } @@ -1154,27 +1154,6 @@ 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) { tries := 0 @@ -1979,11 +1958,11 @@ func (s *RetryLayerChannelStore) GetSidebarCategories(userID string, opts *store } -func (s *RetryLayerChannelStore) GetSidebarCategoriesForTeamForUser(userID string, teamID string, options ...*store.SidebarCategorySearchOpts) (*model.OrderedSidebarCategories, error) { +func (s *RetryLayerChannelStore) GetSidebarCategoriesForTeamForUser(userID string, teamID string) (*model.OrderedSidebarCategories, error) { tries := 0 for { - result, err := s.ChannelStore.GetSidebarCategoriesForTeamForUser(userID, teamID, options...) + result, err := s.ChannelStore.GetSidebarCategoriesForTeamForUser(userID, teamID) if err == nil { return result, nil } @@ -2000,11 +1979,11 @@ func (s *RetryLayerChannelStore) GetSidebarCategoriesForTeamForUser(userID strin } -func (s *RetryLayerChannelStore) GetSidebarCategory(categoryID string, options ...*store.SidebarCategorySearchOpts) (*model.SidebarCategoryWithChannels, error) { +func (s *RetryLayerChannelStore) GetSidebarCategory(categoryID string) (*model.SidebarCategoryWithChannels, error) { tries := 0 for { - result, err := s.ChannelStore.GetSidebarCategory(categoryID, options...) + result, err := s.ChannelStore.GetSidebarCategory(categoryID) if err == nil { return result, nil } @@ -2909,11 +2888,11 @@ func (s *RetryLayerChannelStore) UpdateMultipleMembers(members []*model.ChannelM } -func (s *RetryLayerChannelStore) UpdateSidebarCategories(userID string, teamID string, categories []*model.SidebarCategoryWithChannels, options ...*store.SidebarCategorySearchOpts) ([]*model.SidebarCategoryWithChannels, []*model.SidebarCategoryWithChannels, error) { +func (s *RetryLayerChannelStore) UpdateSidebarCategories(userID string, teamID string, categories []*model.SidebarCategoryWithChannels) ([]*model.SidebarCategoryWithChannels, []*model.SidebarCategoryWithChannels, error) { tries := 0 for { - result, resultVar1, err := s.ChannelStore.UpdateSidebarCategories(userID, teamID, categories, options...) + result, resultVar1, err := s.ChannelStore.UpdateSidebarCategories(userID, teamID, categories) if err == nil { return result, resultVar1, nil } diff --git a/server/channels/store/sqlstore/channel_store.go b/server/channels/store/sqlstore/channel_store.go index 79aecc0f02..b33d200b8a 100644 --- a/server/channels/store/sqlstore/channel_store.go +++ b/server/channels/store/sqlstore/channel_store.go @@ -1190,38 +1190,6 @@ func (s SqlChannelStore) GetChannelsByUser(userId string, includeDeleted bool, l 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) { sql, args, err := s.channelMembersForTeamWithSchemeSelectQuery.Where(sq.Eq{ "ChannelId": channelID, diff --git a/server/channels/store/sqlstore/channel_store_categories.go b/server/channels/store/sqlstore/channel_store_categories.go index 21aba6ed10..ca20e281e3 100644 --- a/server/channels/store/sqlstore/channel_store_categories.go +++ b/server/channels/store/sqlstore/channel_store_categories.go @@ -58,7 +58,11 @@ func (s SqlChannelStore) createInitialSidebarCategoriesT(transaction *sqlxTxWrap From("SidebarCategories"). Where(sq.Eq{ "UserId": userId, - "Type": model.SystemSidebarCategories, + "Type": []model.SidebarCategoryType{ + model.SidebarCategoryFavorites, + model.SidebarCategoryChannels, + model.SidebarCategoryDirectMessages, + }, }) if !opts.ExcludeTeam { @@ -153,15 +157,6 @@ func (s SqlChannelStore) createInitialSidebarCategoriesT(transaction *sqlxTxWrap 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 { sql, args, err := insertBuilder.ToSql() if err != nil { @@ -301,7 +296,7 @@ type sidebarCategoryForJoin struct { ChannelId *string } -func (s SqlChannelStore) CreateSidebarCategory(userId, teamId string, newCategory *model.SidebarCategoryWithChannels, options ...*store.SidebarCategorySearchOpts) (_ *model.SidebarCategoryWithChannels, err error) { +func (s SqlChannelStore) CreateSidebarCategory(userId, teamId string, newCategory *model.SidebarCategoryWithChannels) (_ *model.SidebarCategoryWithChannels, err error) { transaction, err := s.GetMasterX().Beginx() if err != nil { return nil, errors.Wrap(err, "begin_transaction") @@ -309,15 +304,9 @@ func (s SqlChannelStore) CreateSidebarCategory(userId, teamId string, newCategor defer finalizeTransactionX(transaction, &err) - appsCategoryEnabled := false - if len(options) > 0 { - appsCategoryEnabled = options[0].AppsCategoryEnabled - } - opts := &store.SidebarCategorySearchOpts{ - TeamID: teamId, - ExcludeTeam: false, - AppsCategoryEnabled: appsCategoryEnabled, + TeamID: teamId, + ExcludeTeam: false, } categoriesWithOrder, err := s.getSidebarCategoriesT(transaction, userId, opts) if err != nil { @@ -429,14 +418,14 @@ func (s SqlChannelStore) CreateSidebarCategory(userId, teamId string, newCategor return result, nil } -func (s SqlChannelStore) completePopulatingCategoryChannels(category *model.SidebarCategoryWithChannels, appsCategoryEnabled bool) (_ *model.SidebarCategoryWithChannels, err error) { +func (s SqlChannelStore) completePopulatingCategoryChannels(category *model.SidebarCategoryWithChannels) (_ *model.SidebarCategoryWithChannels, err error) { transaction, err := s.GetMasterX().Beginx() if err != nil { return nil, errors.Wrap(err, "begin_transaction") } defer finalizeTransactionX(transaction, &err) - result, err := s.completePopulatingCategoryChannelsT(transaction, category, appsCategoryEnabled) + result, err := s.completePopulatingCategoryChannelsT(transaction, category) if err != nil { return nil, err } @@ -448,38 +437,15 @@ func (s SqlChannelStore) completePopulatingCategoryChannels(category *model.Side return result, nil } -func (s SqlChannelStore) completePopulatingCategoryChannelsT(db dbSelecter, category *model.SidebarCategoryWithChannels, appsCategoryEnabled bool) (*model.SidebarCategoryWithChannels, error) { +func (s SqlChannelStore) completePopulatingCategoryChannelsT(db dbSelecter, category *model.SidebarCategoryWithChannels) (*model.SidebarCategoryWithChannels, error) { if category.Type == model.SidebarCategoryCustom || category.Type == model.SidebarCategoryFavorites { return category, nil } var channelTypeFilter sq.Sqlizer - if category.Type == model.SidebarCategoryApps || category.Type == model.SidebarCategoryDirectMessages { - botChannelsIDs := []string{} - 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}, - } - } + if category.Type == model.SidebarCategoryDirectMessages { + // any DM/GM channels that aren't in any category should be returned as part of the Direct Messages category + channelTypeFilter = sq.Eq{"Channels.Type": []model.ChannelType{model.ChannelTypeDirect, model.ChannelTypeGroup}} } 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 channelTypeFilter = sq.And{ @@ -502,12 +468,6 @@ func (s SqlChannelStore) completePopulatingCategoryChannelsT(db dbSelecter, cate }). Suffix(")") - if !appsCategoryEnabled { - doesNotHaveSidebarChannel = doesNotHaveSidebarChannel.Where( - sq.NotEq{"SidebarCategories.Type": model.SidebarCategoryApps}, - ) - } - channels := []string{} sql, args, err := s.getQueryBuilder(). Select("Id"). @@ -532,7 +492,7 @@ func (s SqlChannelStore) completePopulatingCategoryChannelsT(db dbSelecter, cate return category, nil } -func (s SqlChannelStore) GetSidebarCategory(categoryId string, options ...*store.SidebarCategorySearchOpts) (*model.SidebarCategoryWithChannels, error) { +func (s SqlChannelStore) GetSidebarCategory(categoryId string) (*model.SidebarCategoryWithChannels, error) { sql, args, err := s.getQueryBuilder(). Select("SidebarCategories.*", "SidebarChannels.ChannelId"). From("SidebarCategories"). @@ -561,13 +521,7 @@ func (s SqlChannelStore) GetSidebarCategory(categoryId string, options ...*store result.Channels = append(result.Channels, *category.ChannelId) } } - - appsCategoryEnabled := false - if len(options) > 0 { - appsCategoryEnabled = options[0].AppsCategoryEnabled - } - - return s.completePopulatingCategoryChannels(result, appsCategoryEnabled) + return s.completePopulatingCategoryChannels(result) } func (s SqlChannelStore) getSidebarCategoriesT(db dbSelecter, userId string, opts *store.SidebarCategorySearchOpts) (*model.OrderedSidebarCategories, error) { @@ -599,10 +553,6 @@ func (s SqlChannelStore) getSidebarCategoriesT(db dbSelecter, userId string, opt 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() if err != nil { return nil, errors.Wrap(err, "sidebar_categories_tosql") @@ -633,7 +583,7 @@ func (s SqlChannelStore) getSidebarCategoriesT(db dbSelecter, userId string, opt } } for _, category := range oc.Categories { - if _, err := s.completePopulatingCategoryChannelsT(db, category, opts.AppsCategoryEnabled); err != nil { + if _, err := s.completePopulatingCategoryChannelsT(db, category); err != nil { return nil, err } } @@ -641,16 +591,10 @@ func (s SqlChannelStore) getSidebarCategoriesT(db dbSelecter, userId string, opt return &oc, nil } -func (s SqlChannelStore) GetSidebarCategoriesForTeamForUser(userId, teamId string, options ...*store.SidebarCategorySearchOpts) (*model.OrderedSidebarCategories, error) { - appsCategoryEnabled := false - if len(options) > 0 { - appsCategoryEnabled = options[0].AppsCategoryEnabled - } - +func (s SqlChannelStore) GetSidebarCategoriesForTeamForUser(userId, teamId string) (*model.OrderedSidebarCategories, error) { opts := &store.SidebarCategorySearchOpts{ - TeamID: teamId, - ExcludeTeam: false, - AppsCategoryEnabled: appsCategoryEnabled, + TeamID: teamId, + ExcludeTeam: false, } return s.getSidebarCategoriesT(s.GetReplicaX(), userId, opts) } @@ -744,22 +688,17 @@ func (s SqlChannelStore) UpdateSidebarCategoryOrder(userId, teamId string, categ } //nolint:unparam -func (s SqlChannelStore) UpdateSidebarCategories(userId, teamId string, categories []*model.SidebarCategoryWithChannels, options ...*store.SidebarCategorySearchOpts) (updated []*model.SidebarCategoryWithChannels, original []*model.SidebarCategoryWithChannels, err error) { +func (s SqlChannelStore) UpdateSidebarCategories(userId, teamId string, categories []*model.SidebarCategoryWithChannels) (updated []*model.SidebarCategoryWithChannels, original []*model.SidebarCategoryWithChannels, err error) { transaction, err := s.GetMasterX().Beginx() if err != nil { return nil, nil, errors.Wrap(err, "begin_transaction") } defer finalizeTransactionX(transaction, &err) - opts := &store.SidebarCategorySearchOpts{} - if len(options) > 0 { - opts = options[0] - } - updatedCategories := []*model.SidebarCategoryWithChannels{} originalCategories := []*model.SidebarCategoryWithChannels{} for _, category := range categories { - srcCategory, err2 := s.GetSidebarCategory(category.Id, opts) + srcCategory, err2 := s.GetSidebarCategory(category.Id) if err2 != nil { return nil, nil, errors.Wrap(err2, "failed to find SidebarCategories") } @@ -780,7 +719,7 @@ func (s SqlChannelStore) UpdateSidebarCategories(userId, teamId string, categori destCategory.DisplayName = srcCategory.DisplayName } - if destCategory.Type != model.SidebarCategoryDirectMessages && destCategory.Type != model.SidebarCategoryApps { + if destCategory.Type != model.SidebarCategoryDirectMessages { destCategory.Channels = make([]string, len(category.Channels)) copy(destCategory.Channels, category.Channels) @@ -807,7 +746,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 category.Type != model.SidebarCategoryDirectMessages && destCategory.Type != model.SidebarCategoryApps { + if category.Type != model.SidebarCategoryDirectMessages { // Remove any SidebarChannels entries that were either: // - 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 @@ -904,7 +843,7 @@ func (s SqlChannelStore) UpdateSidebarCategories(userId, teamId string, categori // Ensure Channels are populated for Channels/Direct Messages category if they change for i, updatedCategory := range updatedCategories { - populated, nErr := s.completePopulatingCategoryChannelsT(transaction, updatedCategory, opts.AppsCategoryEnabled) + populated, nErr := s.completePopulatingCategoryChannelsT(transaction, updatedCategory) if nErr != nil { return nil, nil, nErr } diff --git a/server/channels/store/sqlstore/channel_store_categories_test.go b/server/channels/store/sqlstore/channel_store_categories_test.go index 73ba6a1fc7..18eb270054 100644 --- a/server/channels/store/sqlstore/channel_store_categories_test.go +++ b/server/channels/store/sqlstore/channel_store_categories_test.go @@ -11,5 +11,4 @@ import ( func TestChannelStoreCategories(t *testing.T) { StoreTestWithSqlStore(t, storetest.TestChannelStoreCategories) - StoreTestWithSqlStore(t, storetest.TestChannelStoreCategoriesWithAppsCategory) } diff --git a/server/channels/store/store.go b/server/channels/store/store.go index 7be7d778fb..5869071675 100644 --- a/server/channels/store/store.go +++ b/server/channels/store/store.go @@ -198,7 +198,6 @@ type ChannelStore interface { GetChannels(teamID, userID string, opts *model.ChannelSearchOpts) (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) - GetBotChannelsByUser(userID string, opts ChannelSearchOpts) (model.ChannelList, error) GetAllChannelMembersById(id string) ([]string, error) GetAllChannels(page, perPage int, opts ChannelSearchOpts) (model.ChannelListWithTeamData, error) GetAllChannelsCount(opts ChannelSearchOpts) (int64, error) @@ -273,13 +272,13 @@ type ChannelStore interface { ResetAllChannelSchemes() error ClearAllCustomRoleAssignments() error CreateInitialSidebarCategories(userID string, opts *SidebarCategorySearchOpts) (*model.OrderedSidebarCategories, error) - GetSidebarCategoriesForTeamForUser(userID, teamID string, options ...*SidebarCategorySearchOpts) (*model.OrderedSidebarCategories, error) + GetSidebarCategoriesForTeamForUser(userID, teamID string) (*model.OrderedSidebarCategories, error) GetSidebarCategories(userID string, opts *SidebarCategorySearchOpts) (*model.OrderedSidebarCategories, error) - GetSidebarCategory(categoryID string, options ...*SidebarCategorySearchOpts) (*model.SidebarCategoryWithChannels, error) + GetSidebarCategory(categoryID string) (*model.SidebarCategoryWithChannels, error) GetSidebarCategoryOrder(userID, teamID string) ([]string, error) - CreateSidebarCategory(userID, teamID string, newCategory *model.SidebarCategoryWithChannels, options ...*SidebarCategorySearchOpts) (*model.SidebarCategoryWithChannels, error) + CreateSidebarCategory(userID, teamID string, newCategory *model.SidebarCategoryWithChannels) (*model.SidebarCategoryWithChannels, error) UpdateSidebarCategoryOrder(userID, teamID string, categoryOrder []string) error - UpdateSidebarCategories(userID, teamID string, categories []*model.SidebarCategoryWithChannels, options ...*SidebarCategorySearchOpts) ([]*model.SidebarCategoryWithChannels, []*model.SidebarCategoryWithChannels, error) + UpdateSidebarCategories(userID, teamID string, categories []*model.SidebarCategoryWithChannels) ([]*model.SidebarCategoryWithChannels, []*model.SidebarCategoryWithChannels, error) UpdateSidebarChannelsByPreferences(preferences model.Preferences) error DeleteSidebarChannelsByPreferences(preferences model.Preferences) error DeleteSidebarCategory(categoryID string) error @@ -1103,9 +1102,8 @@ type PostReminderMetadata struct { // SidebarCategorySearchOpts contains the options for a graphQL query // to get the sidebar categories. type SidebarCategorySearchOpts struct { - TeamID string - ExcludeTeam bool - AppsCategoryEnabled bool + TeamID string + ExcludeTeam bool } // Ensure store service adapter implements `product.StoreService` diff --git a/server/channels/store/storetest/channel_store_categories_with_apps_category.go b/server/channels/store/storetest/channel_store_categories_with_apps_category.go deleted file mode 100644 index 3cd68b9d60..0000000000 --- a/server/channels/store/storetest/channel_store_categories_with_apps_category.go +++ /dev/null @@ -1,2681 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package storetest - -import ( - "database/sql" - "errors" - "sync" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/mattermost/mattermost/server/public/model" - "github.com/mattermost/mattermost/server/v8/channels/store" -) - -func TestChannelStoreCategoriesWithAppsCategory(t *testing.T, ss store.Store, s SqlStore) { - t.Run("CreateInitialSidebarCategoriesWithAppsCategory", func(t *testing.T) { testCreateInitialSidebarCategoriesWithAppsCategory(t, ss) }) - t.Run("CreateSidebarCategoryWithAppsCategory", func(t *testing.T) { testCreateSidebarCategoryWithAppsCategory(t, ss) }) - t.Run("GetSidebarCategoryWithAppsCategory", func(t *testing.T) { testGetSidebarCategoryWithAppsCategory(t, ss, s) }) - t.Run("GetSidebarCategoriesWithAppsCategory", func(t *testing.T) { testGetSidebarCategoriesWithAppsCategory(t, ss) }) - t.Run("UpdateSidebarCategoriesWithAppsCategory", func(t *testing.T) { testUpdateSidebarCategoriesWithAppsCategory(t, ss) }) - t.Run("ClearSidebarOnTeamLeaveWithAppsCategory", func(t *testing.T) { testClearSidebarOnTeamLeaveWithAppsCategory(t, ss, s) }) - t.Run("DeleteSidebarCategoryWithAppsCategory", func(t *testing.T) { testDeleteSidebarCategoryWithAppsCategory(t, ss, s) }) - t.Run("UpdateSidebarChannelsByPreferencesWithAppsCategory", func(t *testing.T) { testUpdateSidebarChannelsByPreferencesWithAppsCategory(t, ss) }) - t.Run("SidebarCategoryDeadlockWithAppsCategory", func(t *testing.T) { testSidebarCategoryDeadlockWithAppsCategory(t, ss) }) -} - -func testCreateInitialSidebarCategoriesWithAppsCategory(t *testing.T, ss store.Store) { - t.Run("should create initial favorites/channels/DMs/apps categories", func(t *testing.T) { - userId := model.NewId() - - team := setupTeam(t, ss, userId) - - opts := &store.SidebarCategorySearchOpts{ - TeamID: team.Id, - ExcludeTeam: false, - AppsCategoryEnabled: true, - } - - res, nErr := ss.Channel().CreateInitialSidebarCategories(userId, opts) - assert.NoError(t, nErr) - require.Len(t, res.Categories, 4) - assert.Equal(t, model.SidebarCategoryFavorites, res.Categories[0].Type) - assert.Equal(t, model.SidebarCategoryChannels, res.Categories[1].Type) - assert.Equal(t, model.SidebarCategoryDirectMessages, res.Categories[2].Type) - assert.Equal(t, model.SidebarCategoryApps, res.Categories[3].Type) - - res2, err := ss.Channel().GetSidebarCategoriesForTeamForUser(userId, team.Id, opts) - assert.NoError(t, err) - assert.Equal(t, res, res2) - }) - - t.Run("should create initial favorites/channels/DMs/apps categories for multiple users", func(t *testing.T) { - userId := model.NewId() - userId2 := model.NewId() - - team := setupTeam(t, ss, userId, userId2) - - opts := &store.SidebarCategorySearchOpts{ - TeamID: team.Id, - ExcludeTeam: false, - AppsCategoryEnabled: true, - } - res, nErr := ss.Channel().CreateInitialSidebarCategories(userId, opts) - require.NoError(t, nErr) - require.NotEmpty(t, res) - - res, nErr = ss.Channel().CreateInitialSidebarCategories(userId2, opts) - assert.NoError(t, nErr) - assert.Len(t, res.Categories, 4) - assert.Equal(t, model.SidebarCategoryFavorites, res.Categories[0].Type) - assert.Equal(t, model.SidebarCategoryChannels, res.Categories[1].Type) - assert.Equal(t, model.SidebarCategoryDirectMessages, res.Categories[2].Type) - assert.Equal(t, model.SidebarCategoryApps, res.Categories[3].Type) - - res2, err := ss.Channel().GetSidebarCategoriesForTeamForUser(userId2, team.Id, opts) - assert.NoError(t, err) - assert.Equal(t, res, res2) - }) - - t.Run("should create initial favorites/channels/DMs/apps categories on different teams", func(t *testing.T) { - userId := model.NewId() - - team := setupTeam(t, ss, userId) - team2 := setupTeam(t, ss, userId) - - opts := &store.SidebarCategorySearchOpts{ - TeamID: team.Id, - ExcludeTeam: false, - AppsCategoryEnabled: true, - } - res, nErr := ss.Channel().CreateInitialSidebarCategories(userId, opts) - require.NoError(t, nErr) - require.NotEmpty(t, res) - - opts = &store.SidebarCategorySearchOpts{ - TeamID: team2.Id, - ExcludeTeam: false, - AppsCategoryEnabled: true, - } - res, nErr = ss.Channel().CreateInitialSidebarCategories(userId, opts) - assert.NoError(t, nErr) - assert.Len(t, res.Categories, 4) - assert.Equal(t, model.SidebarCategoryFavorites, res.Categories[0].Type) - assert.Equal(t, model.SidebarCategoryChannels, res.Categories[1].Type) - assert.Equal(t, model.SidebarCategoryDirectMessages, res.Categories[2].Type) - assert.Equal(t, model.SidebarCategoryApps, res.Categories[3].Type) - - res2, err := ss.Channel().GetSidebarCategoriesForTeamForUser(userId, team2.Id, opts) - assert.NoError(t, err) - assert.Equal(t, res, res2) - }) - - t.Run("shouldn't create additional categories when ones already exist", func(t *testing.T) { - userId := model.NewId() - - team := setupTeam(t, ss, userId) - - opts := &store.SidebarCategorySearchOpts{ - TeamID: team.Id, - ExcludeTeam: false, - AppsCategoryEnabled: true, - } - res, nErr := ss.Channel().CreateInitialSidebarCategories(userId, opts) - require.NoError(t, nErr) - require.NotEmpty(t, res) - - initialCategories, err := ss.Channel().GetSidebarCategoriesForTeamForUser(userId, team.Id, opts) - require.NoError(t, err) - require.Equal(t, res, initialCategories) - - // Calling CreateInitialSidebarCategories a second time shouldn't create any new categories - res, nErr = ss.Channel().CreateInitialSidebarCategories(userId, opts) - assert.NoError(t, nErr) - assert.NotEmpty(t, res) - - res, err = ss.Channel().GetSidebarCategoriesForTeamForUser(userId, team.Id, opts) - assert.NoError(t, err) - assert.Equal(t, initialCategories.Categories, res.Categories) - }) - - t.Run("shouldn't create additional categories when ones already exist even when ran simultaneously", func(t *testing.T) { - userId := model.NewId() - - team := setupTeam(t, ss, userId) - - opts := &store.SidebarCategorySearchOpts{ - TeamID: team.Id, - ExcludeTeam: false, - AppsCategoryEnabled: true, - } - - var wg sync.WaitGroup - - for i := 0; i < 10; i++ { - wg.Add(1) - - go func() { - defer wg.Done() - - _, _ = ss.Channel().CreateInitialSidebarCategories(userId, opts) - }() - } - - wg.Wait() - - res, err := ss.Channel().GetSidebarCategoriesForTeamForUser(userId, team.Id, opts) - assert.NoError(t, err) - assert.Len(t, res.Categories, 4) - }) - - t.Run("should populate the Favorites category with regular channels", func(t *testing.T) { - userId := model.NewId() - - team := setupTeam(t, ss, userId) - - // Set up two channels, one favorited and one not - channel1, nErr := ss.Channel().Save(&model.Channel{ - TeamId: team.Id, - Type: model.ChannelTypeOpen, - Name: "channel1", - }, 1000) - require.NoError(t, nErr) - _, err := ss.Channel().SaveMember(&model.ChannelMember{ - ChannelId: channel1.Id, - UserId: userId, - NotifyProps: model.GetDefaultChannelNotifyProps(), - }) - require.NoError(t, err) - - channel2, nErr := ss.Channel().Save(&model.Channel{ - TeamId: team.Id, - Type: model.ChannelTypeOpen, - Name: "channel2", - }, 1000) - require.NoError(t, nErr) - _, err = ss.Channel().SaveMember(&model.ChannelMember{ - ChannelId: channel2.Id, - UserId: userId, - NotifyProps: model.GetDefaultChannelNotifyProps(), - }) - require.NoError(t, err) - - nErr = ss.Preference().Save(model.Preferences{ - { - UserId: userId, - Category: model.PreferenceCategoryFavoriteChannel, - Name: channel1.Id, - Value: "true", - }, - }) - require.NoError(t, nErr) - - // Create the categories - opts := &store.SidebarCategorySearchOpts{ - TeamID: team.Id, - ExcludeTeam: false, - AppsCategoryEnabled: true, - } - categories, nErr := ss.Channel().CreateInitialSidebarCategories(userId, opts) - require.NoError(t, nErr) - require.Len(t, categories.Categories, 4) - assert.Equal(t, model.SidebarCategoryFavorites, categories.Categories[0].Type) - assert.Equal(t, []string{channel1.Id}, categories.Categories[0].Channels) - assert.Equal(t, model.SidebarCategoryChannels, categories.Categories[1].Type) - assert.Equal(t, []string{channel2.Id}, categories.Categories[1].Channels) - - // Get and check the categories for channels - categories2, nErr := ss.Channel().GetSidebarCategoriesForTeamForUser(userId, team.Id, opts) - require.NoError(t, nErr) - require.Equal(t, categories, categories2) - }) - - t.Run("should populate the Favorites category in alphabetical order", func(t *testing.T) { - userId := model.NewId() - - team := setupTeam(t, ss, userId) - - // Set up two channels - channel1, nErr := ss.Channel().Save(&model.Channel{ - TeamId: team.Id, - Type: model.ChannelTypeOpen, - Name: "channel1", - DisplayName: "zebra", - }, 1000) - require.NoError(t, nErr) - _, err := ss.Channel().SaveMember(&model.ChannelMember{ - ChannelId: channel1.Id, - UserId: userId, - NotifyProps: model.GetDefaultChannelNotifyProps(), - }) - require.NoError(t, err) - - channel2, nErr := ss.Channel().Save(&model.Channel{ - TeamId: team.Id, - Type: model.ChannelTypeOpen, - Name: "channel2", - DisplayName: "aardvark", - }, 1000) - require.NoError(t, nErr) - _, err = ss.Channel().SaveMember(&model.ChannelMember{ - ChannelId: channel2.Id, - UserId: userId, - NotifyProps: model.GetDefaultChannelNotifyProps(), - }) - require.NoError(t, err) - - nErr = ss.Preference().Save(model.Preferences{ - { - UserId: userId, - Category: model.PreferenceCategoryFavoriteChannel, - Name: channel1.Id, - Value: "true", - }, - { - UserId: userId, - Category: model.PreferenceCategoryFavoriteChannel, - Name: channel2.Id, - Value: "true", - }, - }) - require.NoError(t, nErr) - - // Create the categories - opts := &store.SidebarCategorySearchOpts{ - TeamID: team.Id, - ExcludeTeam: false, - AppsCategoryEnabled: true, - } - categories, nErr := ss.Channel().CreateInitialSidebarCategories(userId, opts) - require.NoError(t, nErr) - require.Len(t, categories.Categories, 4) - assert.Equal(t, model.SidebarCategoryFavorites, categories.Categories[0].Type) - assert.Equal(t, []string{channel2.Id, channel1.Id}, categories.Categories[0].Channels) - - // Get and check the categories for channels - categories2, nErr := ss.Channel().GetSidebarCategoriesForTeamForUser(userId, team.Id, opts) - require.NoError(t, nErr) - require.Equal(t, categories, categories2) - }) - - t.Run("should populate the Favorites category with DMs and GMs", func(t *testing.T) { - userId := model.NewId() - - team := setupTeam(t, ss, userId) - - otherUserId1 := model.NewId() - otherUserId2 := model.NewId() - - // Set up two direct channels, one favorited and one not - dmChannel1, err := ss.Channel().SaveDirectChannel( - &model.Channel{ - Name: model.GetDMNameFromIds(userId, otherUserId1), - Type: model.ChannelTypeDirect, - }, - &model.ChannelMember{ - UserId: userId, - NotifyProps: model.GetDefaultChannelNotifyProps(), - }, - &model.ChannelMember{ - UserId: otherUserId1, - NotifyProps: model.GetDefaultChannelNotifyProps(), - }, - ) - require.NoError(t, err) - - dmChannel2, err := ss.Channel().SaveDirectChannel( - &model.Channel{ - Name: model.GetDMNameFromIds(userId, otherUserId2), - Type: model.ChannelTypeDirect, - }, - &model.ChannelMember{ - UserId: userId, - NotifyProps: model.GetDefaultChannelNotifyProps(), - }, - &model.ChannelMember{ - UserId: otherUserId2, - NotifyProps: model.GetDefaultChannelNotifyProps(), - }, - ) - require.NoError(t, err) - - err = ss.Preference().Save(model.Preferences{ - { - UserId: userId, - Category: model.PreferenceCategoryFavoriteChannel, - Name: dmChannel1.Id, - Value: "true", - }, - }) - require.NoError(t, err) - - // Create the categories - opts := &store.SidebarCategorySearchOpts{ - TeamID: team.Id, - ExcludeTeam: false, - AppsCategoryEnabled: true, - } - categories, nErr := ss.Channel().CreateInitialSidebarCategories(userId, opts) - require.NoError(t, nErr) - require.Len(t, categories.Categories, 4) - assert.Equal(t, model.SidebarCategoryFavorites, categories.Categories[0].Type) - assert.Equal(t, []string{dmChannel1.Id}, categories.Categories[0].Channels) - assert.Equal(t, model.SidebarCategoryDirectMessages, categories.Categories[2].Type) - assert.Equal(t, []string{dmChannel2.Id}, categories.Categories[2].Channels) - - // Get and check the categories for channels - categories2, err := ss.Channel().GetSidebarCategoriesForTeamForUser(userId, team.Id, opts) - require.NoError(t, err) - require.Equal(t, categories, categories2) - }) - - t.Run("should not populate the Favorites category with channels from other teams", func(t *testing.T) { - userId := model.NewId() - - team := setupTeam(t, ss, userId) - team2 := setupTeam(t, ss, userId) - - // Set up a channel on another team and favorite it - channel1, nErr := ss.Channel().Save(&model.Channel{ - TeamId: team2.Id, - Type: model.ChannelTypeOpen, - Name: "channel1", - }, 1000) - require.NoError(t, nErr) - _, err := ss.Channel().SaveMember(&model.ChannelMember{ - ChannelId: channel1.Id, - UserId: userId, - NotifyProps: model.GetDefaultChannelNotifyProps(), - }) - require.NoError(t, err) - - nErr = ss.Preference().Save(model.Preferences{ - { - UserId: userId, - Category: model.PreferenceCategoryFavoriteChannel, - Name: channel1.Id, - Value: "true", - }, - }) - require.NoError(t, nErr) - - // Create the categories - opts := &store.SidebarCategorySearchOpts{ - TeamID: team.Id, - ExcludeTeam: false, - AppsCategoryEnabled: true, - } - categories, nErr := ss.Channel().CreateInitialSidebarCategories(userId, opts) - require.NoError(t, nErr) - require.Len(t, categories.Categories, 4) - assert.Equal(t, model.SidebarCategoryFavorites, categories.Categories[0].Type) - assert.Equal(t, []string{}, categories.Categories[0].Channels) - assert.Equal(t, model.SidebarCategoryChannels, categories.Categories[1].Type) - assert.Equal(t, []string{}, categories.Categories[1].Channels) - - // Get and check the categories for channels - categories2, nErr := ss.Channel().GetSidebarCategoriesForTeamForUser(userId, team.Id, opts) - require.NoError(t, nErr) - require.Equal(t, categories, categories2) - }) - - t.Run("graphQL path to create initial favorites/channels/DMs categories on different teams", func(t *testing.T) { - userId := model.NewId() - - t1 := &model.Team{ - DisplayName: "DisplayName", - Name: NewTestId(), - Email: MakeEmail(), - Type: model.TeamOpen, - InviteId: model.NewId(), - } - t1, err := ss.Team().Save(t1) - require.NoError(t, err) - - m1 := &model.TeamMember{TeamId: t1.Id, UserId: userId} - _, nErr := ss.Team().SaveMember(m1, -1) - require.NoError(t, nErr) - - t2 := &model.Team{ - DisplayName: "DisplayName2", - Name: NewTestId(), - Email: MakeEmail(), - Type: model.TeamOpen, - InviteId: model.NewId(), - } - t2, err = ss.Team().Save(t2) - require.NoError(t, err) - - m2 := &model.TeamMember{TeamId: t2.Id, UserId: userId} - _, nErr = ss.Team().SaveMember(m2, -1) - require.NoError(t, nErr) - - opts := &store.SidebarCategorySearchOpts{ - TeamID: t1.Id, - ExcludeTeam: true, - AppsCategoryEnabled: true, - } - res, nErr := ss.Channel().CreateInitialSidebarCategories(userId, opts) - require.NoError(t, nErr) - require.NotEmpty(t, res) - - for _, cat := range res.Categories { - assert.Equal(t, t2.Id, cat.TeamId) - } - }) -} - -func testCreateSidebarCategoryWithAppsCategory(t *testing.T, ss store.Store) { - t.Run("Creating category without initial categories should fail", func(t *testing.T) { - userId := model.NewId() - teamId := model.NewId() - - opts := &store.SidebarCategorySearchOpts{ - AppsCategoryEnabled: true, - } - - // Create the category - created, err := ss.Channel().CreateSidebarCategory(userId, teamId, &model.SidebarCategoryWithChannels{ - SidebarCategory: model.SidebarCategory{ - DisplayName: model.NewId(), - }, - }, - opts, - ) - require.Error(t, err) - var errNotFound *store.ErrNotFound - require.ErrorAs(t, err, &errNotFound) - require.Nil(t, created) - }) - - t.Run("should place the new category second if Favorites comes first", func(t *testing.T) { - userId := model.NewId() - - team := setupTeam(t, ss, userId) - - opts := &store.SidebarCategorySearchOpts{ - TeamID: team.Id, - ExcludeTeam: false, - AppsCategoryEnabled: true, - } - res, nErr := ss.Channel().CreateInitialSidebarCategories(userId, opts) - require.NoError(t, nErr) - require.NotEmpty(t, res) - - // Create the category - created, err := ss.Channel().CreateSidebarCategory(userId, team.Id, &model.SidebarCategoryWithChannels{ - SidebarCategory: model.SidebarCategory{ - DisplayName: model.NewId(), - }, - }, - opts, - ) - require.NoError(t, err) - - // Confirm that it comes second - res, err = ss.Channel().GetSidebarCategoriesForTeamForUser(userId, team.Id, opts) - require.NoError(t, err) - require.Len(t, res.Categories, 5) - assert.Equal(t, model.SidebarCategoryFavorites, res.Categories[0].Type) - assert.Equal(t, model.SidebarCategoryCustom, res.Categories[1].Type) - assert.Equal(t, created.Id, res.Categories[1].Id) - }) - - t.Run("should place the new category first if Favorites is not first", func(t *testing.T) { - userId := model.NewId() - - team := setupTeam(t, ss, userId) - - opts := &store.SidebarCategorySearchOpts{ - TeamID: team.Id, - ExcludeTeam: false, - AppsCategoryEnabled: true, - } - res, nErr := ss.Channel().CreateInitialSidebarCategories(userId, opts) - require.NoError(t, nErr) - require.NotEmpty(t, res) - - // Re-arrange the categories so that Favorites comes last - categories, err := ss.Channel().GetSidebarCategoriesForTeamForUser(userId, team.Id, opts) - require.NoError(t, err) - require.Len(t, categories.Categories, 4) - require.Equal(t, model.SidebarCategoryFavorites, categories.Categories[0].Type) - - err = ss.Channel().UpdateSidebarCategoryOrder(userId, team.Id, []string{ - categories.Categories[1].Id, - categories.Categories[2].Id, - categories.Categories[3].Id, - categories.Categories[0].Id, - }) - require.NoError(t, err) - - // Create the category - created, err := ss.Channel().CreateSidebarCategory(userId, team.Id, &model.SidebarCategoryWithChannels{ - SidebarCategory: model.SidebarCategory{ - DisplayName: model.NewId(), - }, - }, - opts, - ) - require.NoError(t, err) - - // Confirm that it comes first - res, err = ss.Channel().GetSidebarCategoriesForTeamForUser(userId, team.Id, opts) - require.NoError(t, err) - require.Len(t, res.Categories, 5) - assert.Equal(t, model.SidebarCategoryCustom, res.Categories[0].Type) - assert.Equal(t, created.Id, res.Categories[0].Id) - }) - - t.Run("should create the category with its channels", func(t *testing.T) { - userId := model.NewId() - team := setupTeam(t, ss, userId) - - opts := &store.SidebarCategorySearchOpts{ - TeamID: team.Id, - ExcludeTeam: false, - AppsCategoryEnabled: true, - } - res, nErr := ss.Channel().CreateInitialSidebarCategories(userId, opts) - require.NoError(t, nErr) - require.NotEmpty(t, res) - - // Create some channels - channel1, err := ss.Channel().Save(&model.Channel{ - Type: model.ChannelTypeOpen, - TeamId: team.Id, - Name: model.NewId(), - }, 100) - require.NoError(t, err) - channel2, err := ss.Channel().Save(&model.Channel{ - Type: model.ChannelTypeOpen, - TeamId: team.Id, - Name: model.NewId(), - }, 100) - require.NoError(t, err) - - // Create the category - created, err := ss.Channel().CreateSidebarCategory(userId, team.Id, &model.SidebarCategoryWithChannels{ - SidebarCategory: model.SidebarCategory{ - DisplayName: model.NewId(), - }, - Channels: []string{channel2.Id, channel1.Id}, - }, - opts, - ) - require.NoError(t, err) - assert.Equal(t, []string{channel2.Id, channel1.Id}, created.Channels) - - // Get the channel again to ensure that the SidebarChannels were saved correctly - res2, err := ss.Channel().GetSidebarCategory(created.Id, opts) - require.NoError(t, err) - assert.Equal(t, []string{channel2.Id, channel1.Id}, res2.Channels) - }) - - t.Run("should remove any channels from their previous categories", func(t *testing.T) { - userId := model.NewId() - team := setupTeam(t, ss, userId) - - opts := &store.SidebarCategorySearchOpts{ - TeamID: team.Id, - ExcludeTeam: false, - AppsCategoryEnabled: true, - } - res, nErr := ss.Channel().CreateInitialSidebarCategories(userId, opts) - require.NoError(t, nErr) - require.NotEmpty(t, res) - - categories, err := ss.Channel().GetSidebarCategoriesForTeamForUser(userId, team.Id, opts) - require.NoError(t, err) - require.Len(t, categories.Categories, 4) - - favoritesCategory := categories.Categories[0] - require.Equal(t, model.SidebarCategoryFavorites, favoritesCategory.Type) - channelsCategory := categories.Categories[1] - require.Equal(t, model.SidebarCategoryChannels, channelsCategory.Type) - - // Create some channels - channel1, nErr := ss.Channel().Save(&model.Channel{ - Type: model.ChannelTypeOpen, - TeamId: team.Id, - Name: model.NewId(), - }, 100) - require.NoError(t, nErr) - channel2, nErr := ss.Channel().Save(&model.Channel{ - Type: model.ChannelTypeOpen, - TeamId: team.Id, - Name: model.NewId(), - }, 100) - require.NoError(t, nErr) - - // Assign them to categories - favoritesCategory.Channels = []string{channel1.Id} - channelsCategory.Channels = []string{channel2.Id} - _, _, err = ss.Channel().UpdateSidebarCategories(userId, team.Id, []*model.SidebarCategoryWithChannels{ - favoritesCategory, - channelsCategory, - }, - opts, - ) - require.NoError(t, err) - - // Create the category - created, err := ss.Channel().CreateSidebarCategory(userId, team.Id, &model.SidebarCategoryWithChannels{ - SidebarCategory: model.SidebarCategory{ - DisplayName: model.NewId(), - }, - Channels: []string{channel2.Id, channel1.Id}, - }, - opts, - ) - require.NoError(t, err) - assert.Equal(t, []string{channel2.Id, channel1.Id}, created.Channels) - - // Confirm that the channels were removed from their original categories - res2, err := ss.Channel().GetSidebarCategory(favoritesCategory.Id, opts) - require.NoError(t, err) - assert.Equal(t, []string{}, res2.Channels) - - res2, err = ss.Channel().GetSidebarCategory(channelsCategory.Id, opts) - require.NoError(t, err) - assert.Equal(t, []string{}, res2.Channels) - }) -} - -func testGetSidebarCategoryWithAppsCategory(t *testing.T, ss store.Store, s SqlStore) { - t.Run("should return a custom category with its Channels field set", func(t *testing.T) { - userId := model.NewId() - team := setupTeam(t, ss, userId) - - channelId1 := model.NewId() - channelId2 := model.NewId() - channelId3 := model.NewId() - - opts := &store.SidebarCategorySearchOpts{ - TeamID: team.Id, - ExcludeTeam: false, - AppsCategoryEnabled: true, - } - res, nErr := ss.Channel().CreateInitialSidebarCategories(userId, opts) - require.NoError(t, nErr) - require.NotEmpty(t, res) - - // Create a category and assign some channels to it - created, err := ss.Channel().CreateSidebarCategory(userId, team.Id, &model.SidebarCategoryWithChannels{ - SidebarCategory: model.SidebarCategory{ - UserId: userId, - TeamId: team.Id, - DisplayName: model.NewId(), - }, - Channels: []string{channelId1, channelId2, channelId3}, - }, - opts, - ) - require.NoError(t, err) - require.NotNil(t, created) - - // Ensure that they're returned in order - res2, err := ss.Channel().GetSidebarCategory(created.Id, opts) - assert.NoError(t, err) - assert.Equal(t, created.Id, res2.Id) - assert.Equal(t, model.SidebarCategoryCustom, res2.Type) - assert.Equal(t, created.DisplayName, res2.DisplayName) - assert.Equal(t, []string{channelId1, channelId2, channelId3}, res2.Channels) - }) - - t.Run("should return any orphaned channels with the Channels category", func(t *testing.T) { - userId := model.NewId() - team := setupTeam(t, ss, userId) - - // Create the initial categories and find the channels category - opts := &store.SidebarCategorySearchOpts{ - TeamID: team.Id, - ExcludeTeam: false, - AppsCategoryEnabled: true, - } - res, nErr := ss.Channel().CreateInitialSidebarCategories(userId, opts) - require.NoError(t, nErr) - require.NotEmpty(t, res) - - categories, err := ss.Channel().GetSidebarCategoriesForTeamForUser(userId, team.Id, opts) - require.NoError(t, err) - - channelsCategory := categories.Categories[1] - require.Equal(t, model.SidebarCategoryChannels, channelsCategory.Type) - - // Join some channels - channel1, nErr := ss.Channel().Save(&model.Channel{ - Name: "channel1", - DisplayName: "DEF", - TeamId: team.Id, - Type: model.ChannelTypePrivate, - }, 10) - require.NoError(t, nErr) - _, nErr = ss.Channel().SaveMember(&model.ChannelMember{ - UserId: userId, - ChannelId: channel1.Id, - NotifyProps: model.GetDefaultChannelNotifyProps(), - }) - require.NoError(t, nErr) - - channel2, nErr := ss.Channel().Save(&model.Channel{ - Name: "channel2", - DisplayName: "ABC", - TeamId: team.Id, - Type: model.ChannelTypeOpen, - }, 10) - require.NoError(t, nErr) - _, nErr = ss.Channel().SaveMember(&model.ChannelMember{ - UserId: userId, - ChannelId: channel2.Id, - NotifyProps: model.GetDefaultChannelNotifyProps(), - }) - require.NoError(t, nErr) - - // Confirm that they're not in the Channels category in the DB - var count int64 - countErr := s.GetMasterX().Get(&count, ` - SELECT - COUNT(*) - FROM - SidebarChannels - WHERE - CategoryId = ?`, channelsCategory.Id) - require.NoError(t, countErr) - assert.Equal(t, int64(0), count) - - // Ensure that the Channels are returned in alphabetical order - res2, err := ss.Channel().GetSidebarCategory(channelsCategory.Id, opts) - assert.NoError(t, err) - assert.Equal(t, channelsCategory.Id, res2.Id) - assert.Equal(t, model.SidebarCategoryChannels, channelsCategory.Type) - assert.Equal(t, []string{channel2.Id, channel1.Id}, res2.Channels) - }) - - t.Run("shouldn't return orphaned channels on another team with the Channels category", func(t *testing.T) { - userId := model.NewId() - team := setupTeam(t, ss, userId) - - // Create the initial categories and find the channels category - opts := &store.SidebarCategorySearchOpts{ - TeamID: team.Id, - ExcludeTeam: false, - AppsCategoryEnabled: true, - } - res, nErr := ss.Channel().CreateInitialSidebarCategories(userId, opts) - require.NoError(t, nErr) - require.NotEmpty(t, res) - - categories, err := ss.Channel().GetSidebarCategoriesForTeamForUser(userId, team.Id, opts) - require.NoError(t, err) - require.Equal(t, model.SidebarCategoryChannels, categories.Categories[1].Type) - - channelsCategory := categories.Categories[1] - - // Join a channel on another team - channel1, nErr := ss.Channel().Save(&model.Channel{ - Name: "abc", - TeamId: model.NewId(), - Type: model.ChannelTypeOpen, - }, 10) - require.NoError(t, nErr) - defer ss.Channel().PermanentDelete(channel1.Id) - - _, nErr = ss.Channel().SaveMember(&model.ChannelMember{ - UserId: userId, - ChannelId: channel1.Id, - NotifyProps: model.GetDefaultChannelNotifyProps(), - }) - require.NoError(t, nErr) - - // Ensure that no channels are returned - res2, err := ss.Channel().GetSidebarCategory(channelsCategory.Id, opts) - assert.NoError(t, err) - assert.Equal(t, channelsCategory.Id, res2.Id) - assert.Equal(t, model.SidebarCategoryChannels, channelsCategory.Type) - assert.Len(t, res2.Channels, 0) - }) - - t.Run("shouldn't return non-orphaned channels with the Channels category", func(t *testing.T) { - userId := model.NewId() - team := setupTeam(t, ss, userId) - - opts := &store.SidebarCategorySearchOpts{ - TeamID: team.Id, - ExcludeTeam: false, - AppsCategoryEnabled: true, - } - // Create the initial categories and find the channels category - res, nErr := ss.Channel().CreateInitialSidebarCategories(userId, opts) - require.NoError(t, nErr) - require.NotEmpty(t, res) - - categories, err := ss.Channel().GetSidebarCategoriesForTeamForUser(userId, team.Id, opts) - require.NoError(t, err) - - favoritesCategory := categories.Categories[0] - require.Equal(t, model.SidebarCategoryFavorites, favoritesCategory.Type) - channelsCategory := categories.Categories[1] - require.Equal(t, model.SidebarCategoryChannels, channelsCategory.Type) - - // Join some channels - channel1, nErr := ss.Channel().Save(&model.Channel{ - Name: "channel1", - DisplayName: "DEF", - TeamId: team.Id, - Type: model.ChannelTypePrivate, - }, 10) - require.NoError(t, nErr) - _, nErr = ss.Channel().SaveMember(&model.ChannelMember{ - UserId: userId, - ChannelId: channel1.Id, - NotifyProps: model.GetDefaultChannelNotifyProps(), - }) - require.NoError(t, nErr) - - channel2, nErr := ss.Channel().Save(&model.Channel{ - Name: "channel2", - DisplayName: "ABC", - TeamId: team.Id, - Type: model.ChannelTypeOpen, - }, 10) - require.NoError(t, nErr) - _, nErr = ss.Channel().SaveMember(&model.ChannelMember{ - UserId: userId, - ChannelId: channel2.Id, - NotifyProps: model.GetDefaultChannelNotifyProps(), - }) - require.NoError(t, nErr) - - // And assign one to another category - _, _, err = ss.Channel().UpdateSidebarCategories(userId, team.Id, []*model.SidebarCategoryWithChannels{ - { - SidebarCategory: favoritesCategory.SidebarCategory, - Channels: []string{channel2.Id}, - }, - }, - opts, - ) - require.NoError(t, err) - - // Ensure that the correct channel is returned in the Channels category - res2, err := ss.Channel().GetSidebarCategory(channelsCategory.Id, opts) - assert.NoError(t, err) - assert.Equal(t, channelsCategory.Id, res2.Id) - assert.Equal(t, model.SidebarCategoryChannels, channelsCategory.Type) - assert.Equal(t, []string{channel1.Id}, res2.Channels) - }) - - t.Run("should return any orphaned DM channels with the Direct Messages category", func(t *testing.T) { - userId := model.NewId() - team := setupTeam(t, ss, userId) - - // Create the initial categories and find the DMs category - opts := &store.SidebarCategorySearchOpts{ - TeamID: team.Id, - ExcludeTeam: false, - AppsCategoryEnabled: true, - } - res, nErr := ss.Channel().CreateInitialSidebarCategories(userId, opts) - require.NoError(t, nErr) - require.NotEmpty(t, res) - - categories, err := ss.Channel().GetSidebarCategoriesForTeamForUser(userId, team.Id, opts) - require.NoError(t, err) - require.Equal(t, model.SidebarCategoryDirectMessages, categories.Categories[2].Type) - - dmsCategory := categories.Categories[2] - - // Create a DM - otherUserId := model.NewId() - dmChannel, nErr := ss.Channel().SaveDirectChannel( - &model.Channel{ - Name: model.GetDMNameFromIds(userId, otherUserId), - Type: model.ChannelTypeDirect, - }, - &model.ChannelMember{ - UserId: userId, - NotifyProps: model.GetDefaultChannelNotifyProps(), - }, - &model.ChannelMember{ - UserId: otherUserId, - NotifyProps: model.GetDefaultChannelNotifyProps(), - }, - ) - require.NoError(t, nErr) - - // Ensure that the DM is returned - res2, err := ss.Channel().GetSidebarCategory(dmsCategory.Id, opts) - assert.NoError(t, err) - assert.Equal(t, dmsCategory.Id, res2.Id) - assert.Equal(t, model.SidebarCategoryDirectMessages, res2.Type) - assert.Equal(t, []string{dmChannel.Id}, res2.Channels) - }) - - t.Run("should return any orphaned GM channels with the Direct Messages category", func(t *testing.T) { - userId := model.NewId() - team := setupTeam(t, ss, userId) - - // Create the initial categories and find the DMs category - opts := &store.SidebarCategorySearchOpts{ - TeamID: team.Id, - ExcludeTeam: false, - AppsCategoryEnabled: true, - } - res, nErr := ss.Channel().CreateInitialSidebarCategories(userId, opts) - require.NoError(t, nErr) - require.NotEmpty(t, res) - - categories, err := ss.Channel().GetSidebarCategoriesForTeamForUser(userId, team.Id, opts) - require.NoError(t, err) - require.Equal(t, model.SidebarCategoryDirectMessages, categories.Categories[2].Type) - - dmsCategory := categories.Categories[2] - - // Create a GM - gmChannel, nErr := ss.Channel().Save(&model.Channel{ - Name: "abc", - TeamId: "", - Type: model.ChannelTypeGroup, - }, 10) - require.NoError(t, nErr) - defer ss.Channel().PermanentDelete(gmChannel.Id) - _, nErr = ss.Channel().SaveMember(&model.ChannelMember{ - UserId: userId, - ChannelId: gmChannel.Id, - NotifyProps: model.GetDefaultChannelNotifyProps(), - }) - require.NoError(t, nErr) - - // Ensure that the DM is returned - res2, err := ss.Channel().GetSidebarCategory(dmsCategory.Id, opts) - assert.NoError(t, err) - assert.Equal(t, dmsCategory.Id, res2.Id) - assert.Equal(t, model.SidebarCategoryDirectMessages, res2.Type) - assert.Equal(t, []string{gmChannel.Id}, res2.Channels) - }) - - t.Run("should return orphaned DM channels in the DMs category which are in a custom category on another team", func(t *testing.T) { - userId := model.NewId() - team := setupTeam(t, ss, userId) - - // Create the initial categories and find the DMs category - opts := &store.SidebarCategorySearchOpts{ - TeamID: team.Id, - ExcludeTeam: false, - AppsCategoryEnabled: true, - } - res, nErr := ss.Channel().CreateInitialSidebarCategories(userId, opts) - require.NoError(t, nErr) - require.NotEmpty(t, res) - - categories, err := ss.Channel().GetSidebarCategoriesForTeamForUser(userId, team.Id, opts) - require.NoError(t, err) - require.Equal(t, model.SidebarCategoryDirectMessages, categories.Categories[2].Type) - - dmsCategory := categories.Categories[2] - - // Create a DM - otherUserId := model.NewId() - dmChannel, nErr := ss.Channel().SaveDirectChannel( - &model.Channel{ - Name: model.GetDMNameFromIds(userId, otherUserId), - Type: model.ChannelTypeDirect, - }, - &model.ChannelMember{ - UserId: userId, - NotifyProps: model.GetDefaultChannelNotifyProps(), - }, - &model.ChannelMember{ - UserId: otherUserId, - NotifyProps: model.GetDefaultChannelNotifyProps(), - }, - ) - require.NoError(t, nErr) - - // Create another team and assign the DM to a custom category on that team - otherTeam := setupTeam(t, ss, userId) - opts = &store.SidebarCategorySearchOpts{ - TeamID: otherTeam.Id, - ExcludeTeam: false, - AppsCategoryEnabled: true, - } - res, nErr = ss.Channel().CreateInitialSidebarCategories(userId, opts) - require.NoError(t, nErr) - require.NotEmpty(t, res) - - _, err = ss.Channel().CreateSidebarCategory(userId, otherTeam.Id, &model.SidebarCategoryWithChannels{ - SidebarCategory: model.SidebarCategory{ - UserId: userId, - TeamId: team.Id, - }, - Channels: []string{dmChannel.Id}, - }, - opts, - ) - require.NoError(t, err) - - // Ensure that the DM is returned with the DMs category on the original team - res2, err := ss.Channel().GetSidebarCategory(dmsCategory.Id, opts) - assert.NoError(t, err) - assert.Equal(t, dmsCategory.Id, res2.Id) - assert.Equal(t, model.SidebarCategoryDirectMessages, res2.Type) - assert.Equal(t, []string{dmChannel.Id}, res2.Channels) - }) - - t.Run("should return any orphaned DM Bot channels with the Apps category", func(t *testing.T) { - userId := model.NewId() - team := setupTeam(t, ss, userId) - - // Create the initial categories and find the DMs category - opts := &store.SidebarCategorySearchOpts{ - TeamID: team.Id, - ExcludeTeam: false, - AppsCategoryEnabled: true, - } - res, nErr := ss.Channel().CreateInitialSidebarCategories(userId, opts) - require.NoError(t, nErr) - require.NotEmpty(t, res) - - categories, err := ss.Channel().GetSidebarCategoriesForTeamForUser(userId, team.Id, opts) - require.NoError(t, err) - require.Equal(t, model.SidebarCategoryApps, categories.Categories[3].Type) - - appsCategory := categories.Categories[3] - - // Create a Bot user - botId := model.NewId() - botUser, _ := makeBotWithUser(t, ss, &model.Bot{ - Username: botId + "somebot", - Description: "a bot", - OwnerId: botId, - LastIconUpdate: model.GetMillis(), - }) - - // Create a DM with Bot - dmChannel, nErr := ss.Channel().SaveDirectChannel( - &model.Channel{ - Name: model.GetDMNameFromIds(userId, botUser.UserId), - Type: model.ChannelTypeDirect, - }, - &model.ChannelMember{ - UserId: userId, - NotifyProps: model.GetDefaultChannelNotifyProps(), - }, - &model.ChannelMember{ - UserId: botUser.UserId, - NotifyProps: model.GetDefaultChannelNotifyProps(), - }, - ) - require.NoError(t, nErr) - - // Ensure that the DM Bot is returned - res2, err := ss.Channel().GetSidebarCategory(appsCategory.Id, opts) - assert.NoError(t, err) - assert.Equal(t, appsCategory.Id, res2.Id) - assert.Equal(t, model.SidebarCategoryApps, res2.Type) - assert.Equal(t, []string{dmChannel.Id}, res2.Channels) - }) - - t.Run("should return orphaned DM Bot channels in the Apps category which are in a custom category on another team", func(t *testing.T) { - userId := model.NewId() - team := setupTeam(t, ss, userId) - - // Create the initial categories and find the DMs category - opts := &store.SidebarCategorySearchOpts{ - TeamID: team.Id, - ExcludeTeam: false, - AppsCategoryEnabled: true, - } - res, nErr := ss.Channel().CreateInitialSidebarCategories(userId, opts) - require.NoError(t, nErr) - require.NotEmpty(t, res) - - categories, err := ss.Channel().GetSidebarCategoriesForTeamForUser(userId, team.Id, opts) - require.NoError(t, err) - require.Equal(t, model.SidebarCategoryApps, categories.Categories[3].Type) - - appsCategory := categories.Categories[3] - - // Create a Bot user - botId := model.NewId() - botUser, _ := makeBotWithUser(t, ss, &model.Bot{ - Username: botId + "somebot", - Description: "a bot", - OwnerId: botId, - LastIconUpdate: model.GetMillis(), - }) - - // Create a DM with Bot - dmChannel, nErr := ss.Channel().SaveDirectChannel( - &model.Channel{ - Name: model.GetDMNameFromIds(userId, botUser.UserId), - Type: model.ChannelTypeDirect, - }, - &model.ChannelMember{ - UserId: userId, - NotifyProps: model.GetDefaultChannelNotifyProps(), - }, - &model.ChannelMember{ - UserId: botUser.UserId, - NotifyProps: model.GetDefaultChannelNotifyProps(), - }, - ) - require.NoError(t, nErr) - - // Create another team and assign the DM Bot to a custom category on that team - otherTeam := setupTeam(t, ss, userId) - opts = &store.SidebarCategorySearchOpts{ - TeamID: otherTeam.Id, - ExcludeTeam: false, - AppsCategoryEnabled: true, - } - res, nErr = ss.Channel().CreateInitialSidebarCategories(userId, opts) - require.NoError(t, nErr) - require.NotEmpty(t, res) - - _, err = ss.Channel().CreateSidebarCategory(userId, otherTeam.Id, &model.SidebarCategoryWithChannels{ - SidebarCategory: model.SidebarCategory{ - UserId: userId, - TeamId: team.Id, - }, - Channels: []string{dmChannel.Id}, - }, - opts, - ) - require.NoError(t, err) - - // Ensure that the DM is returned with the DMs category on the original team - res2, err := ss.Channel().GetSidebarCategory(appsCategory.Id, opts) - assert.NoError(t, err) - assert.Equal(t, appsCategory.Id, res2.Id) - assert.Equal(t, model.SidebarCategoryApps, res2.Type) - assert.Equal(t, []string{dmChannel.Id}, res2.Channels) - }) -} - -func testGetSidebarCategoriesWithAppsCategory(t *testing.T, ss store.Store) { - t.Run("should return channels in the same order between different ways of getting categories", func(t *testing.T) { - userId := model.NewId() - team := setupTeam(t, ss, userId) - - opts := &store.SidebarCategorySearchOpts{ - TeamID: team.Id, - ExcludeTeam: false, - AppsCategoryEnabled: true, - } - res, nErr := ss.Channel().CreateInitialSidebarCategories(userId, opts) - require.NoError(t, nErr) - require.NotEmpty(t, res) - - channelIds := []string{ - model.NewId(), - model.NewId(), - model.NewId(), - } - - newCategory, err := ss.Channel().CreateSidebarCategory(userId, team.Id, &model.SidebarCategoryWithChannels{ - Channels: channelIds, - }, - opts, - ) - require.NoError(t, err) - require.NotNil(t, newCategory) - - gotCategory, err := ss.Channel().GetSidebarCategory(newCategory.Id, opts) - require.NoError(t, err) - - res, err = ss.Channel().GetSidebarCategoriesForTeamForUser(userId, team.Id, opts) - require.NoError(t, err) - require.Len(t, res.Categories, 5) - - require.Equal(t, model.SidebarCategoryCustom, res.Categories[1].Type) - - // This looks unnecessary, but I was getting different results from some of these before - assert.Equal(t, newCategory.Channels, res.Categories[1].Channels) - assert.Equal(t, gotCategory.Channels, res.Categories[1].Channels) - assert.Equal(t, channelIds, res.Categories[1].Channels) - }) - t.Run("should not return categories for teams deleted, or no longer a member", func(t *testing.T) { - userId := model.NewId() - - teamMember1 := setupTeam(t, ss, userId) - teamMember2 := setupTeam(t, ss, userId) - teamDeleted := setupTeam(t, ss, userId) - teamDeleted.DeleteAt = model.GetMillis() - ss.Team().Update(teamDeleted) - teamNotMember := setupTeam(t, ss) - teamDeletedMember := setupTeam(t, ss, userId) - - members, err := ss.Team().GetMembersByIds(teamDeletedMember.Id, []string{userId}, nil) - require.NoError(t, err) - require.NotEmpty(t, members) - member := members[0] - member.DeleteAt = model.GetMillis() - ss.Team().UpdateMember(member) - - teamIds := []string{ - teamMember1.Id, - teamMember2.Id, - teamDeleted.Id, - teamNotMember.Id, - teamDeletedMember.Id, - } - - for _, id := range teamIds { - res, nErr := ss.Channel().CreateInitialSidebarCategories(userId, &store.SidebarCategorySearchOpts{TeamID: id, AppsCategoryEnabled: true}) - require.NoError(t, nErr) - require.NotEmpty(t, res) - } - - opts := &store.SidebarCategorySearchOpts{ - TeamID: teamMember1.Id, - ExcludeTeam: false, - AppsCategoryEnabled: true, - } - - // Team member and not exclude - res, err := ss.Channel().GetSidebarCategories(userId, opts) - require.NoError(t, err) - assert.Equal(t, 4, len(res.Categories)) - - // No team member and not exclude - opts.TeamID = teamDeleted.Id - res, err = ss.Channel().GetSidebarCategories(userId, opts) - require.NoError(t, err) - assert.Equal(t, 0, len(res.Categories)) - - // No team member and exclude - opts.ExcludeTeam = true - res, err = ss.Channel().GetSidebarCategories(userId, opts) - require.NoError(t, err) - assert.Equal(t, 8, len(res.Categories)) - - // Team member and exclude - opts.TeamID = teamMember1.Id - res, err = ss.Channel().GetSidebarCategories(userId, opts) - require.NoError(t, err) - assert.Equal(t, 4, len(res.Categories)) - }) -} - -func testUpdateSidebarCategoriesWithAppsCategory(t *testing.T, ss store.Store) { - t.Run("ensure the query to update SidebarCategories hasn't been polluted by UpdateSidebarCategoryOrder", func(t *testing.T) { - userId := model.NewId() - team := setupTeam(t, ss, userId) - - // Create the initial categories - opts := &store.SidebarCategorySearchOpts{ - TeamID: team.Id, - ExcludeTeam: false, - AppsCategoryEnabled: true, - } - res, err := ss.Channel().CreateInitialSidebarCategories(userId, opts) - require.NoError(t, err) - require.NotEmpty(t, res) - - initialCategories, err := ss.Channel().GetSidebarCategoriesForTeamForUser(userId, team.Id, opts) - require.NoError(t, err) - - favoritesCategory := initialCategories.Categories[0] - channelsCategory := initialCategories.Categories[1] - dmsCategory := initialCategories.Categories[2] - appsCategory := initialCategories.Categories[3] - - // And then update one of them - updated, _, err := ss.Channel().UpdateSidebarCategories(userId, team.Id, []*model.SidebarCategoryWithChannels{ - channelsCategory, - }, - opts, - ) - require.NoError(t, err) - assert.Equal(t, channelsCategory, updated[0]) - assert.Equal(t, "Channels", updated[0].DisplayName) - - // And then reorder the categories - err = ss.Channel().UpdateSidebarCategoryOrder(userId, team.Id, []string{dmsCategory.Id, favoritesCategory.Id, channelsCategory.Id, appsCategory.Id}) - require.NoError(t, err) - - // Which somehow blanks out stuff because ??? - got, err := ss.Channel().GetSidebarCategory(favoritesCategory.Id, opts) - require.NoError(t, err) - assert.Equal(t, "Favorites", got.DisplayName) - }) - - t.Run("categories should be returned in their original order", func(t *testing.T) { - userId := model.NewId() - team := setupTeam(t, ss, userId) - - // Create the initial categories - opts := &store.SidebarCategorySearchOpts{ - TeamID: team.Id, - ExcludeTeam: false, - AppsCategoryEnabled: true, - } - res, err := ss.Channel().CreateInitialSidebarCategories(userId, opts) - require.NoError(t, err) - require.NotEmpty(t, res) - - initialCategories, err := ss.Channel().GetSidebarCategoriesForTeamForUser(userId, team.Id, opts) - require.NoError(t, err) - - favoritesCategory := initialCategories.Categories[0] - channelsCategory := initialCategories.Categories[1] - dmsCategory := initialCategories.Categories[2] - appsCategory := initialCategories.Categories[3] - - // And then update them - updatedCategories, _, err := ss.Channel().UpdateSidebarCategories(userId, team.Id, []*model.SidebarCategoryWithChannels{ - favoritesCategory, - channelsCategory, - dmsCategory, - appsCategory, - }) - assert.NoError(t, err) - assert.Equal(t, favoritesCategory.Id, updatedCategories[0].Id) - assert.Equal(t, channelsCategory.Id, updatedCategories[1].Id) - assert.Equal(t, dmsCategory.Id, updatedCategories[2].Id) - assert.Equal(t, appsCategory.Id, updatedCategories[3].Id) - }) - - t.Run("should silently fail to update read only fields", func(t *testing.T) { - userId := model.NewId() - team := setupTeam(t, ss, userId) - - opts := &store.SidebarCategorySearchOpts{ - TeamID: team.Id, - ExcludeTeam: false, - AppsCategoryEnabled: true, - } - res, nErr := ss.Channel().CreateInitialSidebarCategories(userId, opts) - require.NoError(t, nErr) - require.NotEmpty(t, res) - - initialCategories, err := ss.Channel().GetSidebarCategoriesForTeamForUser(userId, team.Id, opts) - require.NoError(t, err) - - favoritesCategory := initialCategories.Categories[0] - channelsCategory := initialCategories.Categories[1] - dmsCategory := initialCategories.Categories[2] - appsCategory := initialCategories.Categories[3] - - customCategory, err := ss.Channel().CreateSidebarCategory(userId, team.Id, &model.SidebarCategoryWithChannels{}, opts) - require.NoError(t, err) - - categoriesToUpdate := []*model.SidebarCategoryWithChannels{ - // Try to change the type of Favorites - { - SidebarCategory: model.SidebarCategory{ - Id: favoritesCategory.Id, - DisplayName: "something else", - }, - Channels: favoritesCategory.Channels, - }, - // Try to change the type of Channels - { - SidebarCategory: model.SidebarCategory{ - Id: channelsCategory.Id, - Type: model.SidebarCategoryDirectMessages, - }, - Channels: channelsCategory.Channels, - }, - // Try to change the Channels of DMs - { - SidebarCategory: dmsCategory.SidebarCategory, - Channels: []string{"fakechannel"}, - }, - // Try to change the Channels of Apps - { - SidebarCategory: appsCategory.SidebarCategory, - Channels: []string{"fakechannel"}, - }, - // Try to change the UserId/TeamId of a custom category - { - SidebarCategory: model.SidebarCategory{ - Id: customCategory.Id, - UserId: model.NewId(), - TeamId: model.NewId(), - Sorting: customCategory.Sorting, - DisplayName: customCategory.DisplayName, - }, - Channels: customCategory.Channels, - }, - } - - updatedCategories, _, err := ss.Channel().UpdateSidebarCategories(userId, team.Id, categoriesToUpdate, opts) - assert.NoError(t, err) - - assert.NotEqual(t, "Favorites", categoriesToUpdate[0].DisplayName) - assert.Equal(t, "Favorites", updatedCategories[0].DisplayName) - assert.NotEqual(t, model.SidebarCategoryChannels, categoriesToUpdate[1].Type) - assert.Equal(t, model.SidebarCategoryChannels, updatedCategories[1].Type) - assert.NotEqual(t, []string{}, categoriesToUpdate[2].Channels) - assert.Equal(t, []string{}, updatedCategories[2].Channels) - assert.NotEqual(t, []string{}, categoriesToUpdate[3].Channels) - assert.Equal(t, []string{}, updatedCategories[3].Channels) - assert.NotEqual(t, userId, categoriesToUpdate[4].UserId) - assert.Equal(t, userId, updatedCategories[4].UserId) - }) - - t.Run("should add and remove favorites preferences based on the Favorites category", func(t *testing.T) { - userId := model.NewId() - team := setupTeam(t, ss, userId) - - // Create the initial categories and find the favorites category - opts := &store.SidebarCategorySearchOpts{ - TeamID: team.Id, - ExcludeTeam: false, - AppsCategoryEnabled: true, - } - res, nErr := ss.Channel().CreateInitialSidebarCategories(userId, opts) - require.NoError(t, nErr) - require.NotEmpty(t, res) - - categories, err := ss.Channel().GetSidebarCategoriesForTeamForUser(userId, team.Id, opts) - require.NoError(t, err) - - favoritesCategory := categories.Categories[0] - require.Equal(t, model.SidebarCategoryFavorites, favoritesCategory.Type) - - // Join a channel - channel, nErr := ss.Channel().Save(&model.Channel{ - Name: "channel", - Type: model.ChannelTypeOpen, - TeamId: team.Id, - }, 10) - require.NoError(t, nErr) - _, nErr = ss.Channel().SaveMember(&model.ChannelMember{ - UserId: userId, - ChannelId: channel.Id, - NotifyProps: model.GetDefaultChannelNotifyProps(), - }) - require.NoError(t, nErr) - - // Assign it to favorites - _, _, err = ss.Channel().UpdateSidebarCategories(userId, team.Id, []*model.SidebarCategoryWithChannels{ - { - SidebarCategory: favoritesCategory.SidebarCategory, - Channels: []string{channel.Id}, - }, - }, - opts, - ) - assert.NoError(t, err) - - res2, nErr := ss.Preference().Get(userId, model.PreferenceCategoryFavoriteChannel, channel.Id) - assert.NoError(t, nErr) - assert.NotNil(t, res2) - assert.Equal(t, "true", res2.Value) - - // And then remove it - channelsCategory := categories.Categories[1] - require.Equal(t, model.SidebarCategoryChannels, channelsCategory.Type) - - _, _, err = ss.Channel().UpdateSidebarCategories(userId, team.Id, []*model.SidebarCategoryWithChannels{ - { - SidebarCategory: channelsCategory.SidebarCategory, - Channels: []string{channel.Id}, - }, - }, - opts, - ) - assert.NoError(t, err) - - res2, nErr = ss.Preference().Get(userId, model.PreferenceCategoryFavoriteChannel, channel.Id) - assert.Error(t, nErr) - assert.True(t, errors.Is(nErr, sql.ErrNoRows)) - assert.Nil(t, res2) - }) - - t.Run("should add and remove favorites preferences for DMs", func(t *testing.T) { - userId := model.NewId() - team := setupTeam(t, ss, userId) - - // Create the initial categories and find the favorites category - opts := &store.SidebarCategorySearchOpts{ - TeamID: team.Id, - ExcludeTeam: false, - AppsCategoryEnabled: true, - } - res, nErr := ss.Channel().CreateInitialSidebarCategories(userId, opts) - require.NoError(t, nErr) - require.NotEmpty(t, res) - - categories, err := ss.Channel().GetSidebarCategoriesForTeamForUser(userId, team.Id, opts) - require.NoError(t, err) - - favoritesCategory := categories.Categories[0] - require.Equal(t, model.SidebarCategoryFavorites, favoritesCategory.Type) - - // Create a direct channel - otherUserId := model.NewId() - - dmChannel, nErr := ss.Channel().SaveDirectChannel( - &model.Channel{ - Name: model.GetDMNameFromIds(userId, otherUserId), - Type: model.ChannelTypeDirect, - }, - &model.ChannelMember{ - UserId: userId, - NotifyProps: model.GetDefaultChannelNotifyProps(), - }, - &model.ChannelMember{ - UserId: otherUserId, - NotifyProps: model.GetDefaultChannelNotifyProps(), - }, - ) - assert.NoError(t, nErr) - - // Assign it to favorites - _, _, err = ss.Channel().UpdateSidebarCategories(userId, team.Id, []*model.SidebarCategoryWithChannels{ - { - SidebarCategory: favoritesCategory.SidebarCategory, - Channels: []string{dmChannel.Id}, - }, - }, - opts, - ) - assert.NoError(t, err) - - res2, nErr := ss.Preference().Get(userId, model.PreferenceCategoryFavoriteChannel, dmChannel.Id) - assert.NoError(t, nErr) - assert.NotNil(t, res2) - assert.Equal(t, "true", res2.Value) - - // And then remove it - dmsCategory := categories.Categories[2] - require.Equal(t, model.SidebarCategoryDirectMessages, dmsCategory.Type) - - _, _, err = ss.Channel().UpdateSidebarCategories(userId, team.Id, []*model.SidebarCategoryWithChannels{ - { - SidebarCategory: dmsCategory.SidebarCategory, - Channels: []string{dmChannel.Id}, - }, - }, - opts, - ) - assert.NoError(t, err) - - res2, nErr = ss.Preference().Get(userId, model.PreferenceCategoryFavoriteChannel, dmChannel.Id) - assert.Error(t, nErr) - assert.True(t, errors.Is(nErr, sql.ErrNoRows)) - assert.Nil(t, res2) - }) - - t.Run("should add and remove favorites preferences, even if the channel is already favorited in preferences", func(t *testing.T) { - userId := model.NewId() - team := setupTeam(t, ss, userId) - team2 := setupTeam(t, ss, userId) - - // Create the initial categories and find the favorites categories in each team - opts := &store.SidebarCategorySearchOpts{ - TeamID: team.Id, - ExcludeTeam: false, - AppsCategoryEnabled: true, - } - res, nErr := ss.Channel().CreateInitialSidebarCategories(userId, opts) - require.NoError(t, nErr) - require.NotEmpty(t, res) - - categories, err := ss.Channel().GetSidebarCategoriesForTeamForUser(userId, team.Id, opts) - require.NoError(t, err) - - favoritesCategory := categories.Categories[0] - require.Equal(t, model.SidebarCategoryFavorites, favoritesCategory.Type) - - opts = &store.SidebarCategorySearchOpts{ - TeamID: team2.Id, - ExcludeTeam: false, - AppsCategoryEnabled: true, - } - res, nErr = ss.Channel().CreateInitialSidebarCategories(userId, opts) - require.NoError(t, nErr) - require.NotEmpty(t, res) - - categories2, err := ss.Channel().GetSidebarCategoriesForTeamForUser(userId, team2.Id, opts) - require.NoError(t, err) - - favoritesCategory2 := categories2.Categories[0] - require.Equal(t, model.SidebarCategoryFavorites, favoritesCategory2.Type) - - // Create a direct channel - otherUserId := model.NewId() - - dmChannel, nErr := ss.Channel().SaveDirectChannel( - &model.Channel{ - Name: model.GetDMNameFromIds(userId, otherUserId), - Type: model.ChannelTypeDirect, - }, - &model.ChannelMember{ - UserId: userId, - NotifyProps: model.GetDefaultChannelNotifyProps(), - }, - &model.ChannelMember{ - UserId: otherUserId, - NotifyProps: model.GetDefaultChannelNotifyProps(), - }, - ) - assert.NoError(t, nErr) - - // Assign it to favorites on the first team. The favorites preference gets set for all teams. - _, _, err = ss.Channel().UpdateSidebarCategories(userId, team.Id, []*model.SidebarCategoryWithChannels{ - { - SidebarCategory: favoritesCategory.SidebarCategory, - Channels: []string{dmChannel.Id}, - }, - }, - opts, - ) - assert.NoError(t, err) - - res2, nErr := ss.Preference().Get(userId, model.PreferenceCategoryFavoriteChannel, dmChannel.Id) - assert.NoError(t, nErr) - assert.NotNil(t, res2) - assert.Equal(t, "true", res2.Value) - - // Assign it to favorites on the second team. The favorites preference is already set. - updated, _, err := ss.Channel().UpdateSidebarCategories(userId, team.Id, []*model.SidebarCategoryWithChannels{ - { - SidebarCategory: favoritesCategory2.SidebarCategory, - Channels: []string{dmChannel.Id}, - }, - }, - opts, - ) - assert.NoError(t, err) - assert.Equal(t, []string{dmChannel.Id}, updated[0].Channels) - - res2, nErr = ss.Preference().Get(userId, model.PreferenceCategoryFavoriteChannel, dmChannel.Id) - assert.NoError(t, nErr) - assert.NotNil(t, res2) - assert.Equal(t, "true", res2.Value) - - // Remove it from favorites on the first team. This clears the favorites preference for all teams. - _, _, err = ss.Channel().UpdateSidebarCategories(userId, team.Id, []*model.SidebarCategoryWithChannels{ - { - SidebarCategory: favoritesCategory.SidebarCategory, - Channels: []string{}, - }, - }, - opts, - ) - assert.NoError(t, err) - - res2, nErr = ss.Preference().Get(userId, model.PreferenceCategoryFavoriteChannel, dmChannel.Id) - require.Error(t, nErr) - assert.Nil(t, res2) - - // Remove it from favorites on the second team. The favorites preference was already deleted. - _, _, err = ss.Channel().UpdateSidebarCategories(userId, team.Id, []*model.SidebarCategoryWithChannels{ - { - SidebarCategory: favoritesCategory2.SidebarCategory, - Channels: []string{}, - }, - }, - opts, - ) - assert.NoError(t, err) - - res2, nErr = ss.Preference().Get(userId, model.PreferenceCategoryFavoriteChannel, dmChannel.Id) - require.Error(t, nErr) - assert.Nil(t, res2) - }) - - t.Run("should not affect other users' favorites preferences", func(t *testing.T) { - userId := model.NewId() - userId2 := model.NewId() - team := setupTeam(t, ss, userId, userId2) - - // Create the initial categories and find the favorites category - opts := &store.SidebarCategorySearchOpts{ - TeamID: team.Id, - ExcludeTeam: false, - AppsCategoryEnabled: true, - } - res, nErr := ss.Channel().CreateInitialSidebarCategories(userId, opts) - require.NoError(t, nErr) - require.NotEmpty(t, res) - - categories, err := ss.Channel().GetSidebarCategoriesForTeamForUser(userId, team.Id, opts) - require.NoError(t, err) - - favoritesCategory := categories.Categories[0] - require.Equal(t, model.SidebarCategoryFavorites, favoritesCategory.Type) - channelsCategory := categories.Categories[1] - require.Equal(t, model.SidebarCategoryChannels, channelsCategory.Type) - - // Create the other users' categories - res, nErr = ss.Channel().CreateInitialSidebarCategories(userId2, opts) - require.NoError(t, nErr) - require.NotEmpty(t, res) - - categories2, err := ss.Channel().GetSidebarCategoriesForTeamForUser(userId2, team.Id, opts) - require.NoError(t, err) - - favoritesCategory2 := categories2.Categories[0] - require.Equal(t, model.SidebarCategoryFavorites, favoritesCategory2.Type) - channelsCategory2 := categories2.Categories[1] - require.Equal(t, model.SidebarCategoryChannels, channelsCategory2.Type) - - // Have both users join a channel - channel, nErr := ss.Channel().Save(&model.Channel{ - Name: "channel", - Type: model.ChannelTypeOpen, - TeamId: team.Id, - }, 10) - require.NoError(t, nErr) - _, nErr = ss.Channel().SaveMember(&model.ChannelMember{ - UserId: userId, - ChannelId: channel.Id, - NotifyProps: model.GetDefaultChannelNotifyProps(), - }) - require.NoError(t, nErr) - _, nErr = ss.Channel().SaveMember(&model.ChannelMember{ - UserId: userId2, - ChannelId: channel.Id, - NotifyProps: model.GetDefaultChannelNotifyProps(), - }) - require.NoError(t, nErr) - - // Have user1 favorite it - _, _, err = ss.Channel().UpdateSidebarCategories(userId, team.Id, []*model.SidebarCategoryWithChannels{ - { - SidebarCategory: favoritesCategory.SidebarCategory, - Channels: []string{channel.Id}, - }, - { - SidebarCategory: channelsCategory.SidebarCategory, - Channels: []string{}, - }, - }, - opts, - ) - assert.NoError(t, err) - - res2, nErr := ss.Preference().Get(userId, model.PreferenceCategoryFavoriteChannel, channel.Id) - assert.NoError(t, nErr) - assert.NotNil(t, res2) - assert.Equal(t, "true", res2.Value) - - res2, nErr = ss.Preference().Get(userId2, model.PreferenceCategoryFavoriteChannel, channel.Id) - assert.True(t, errors.Is(nErr, sql.ErrNoRows)) - assert.Nil(t, res2) - - // And user2 favorite it - _, _, err = ss.Channel().UpdateSidebarCategories(userId2, team.Id, []*model.SidebarCategoryWithChannels{ - { - SidebarCategory: favoritesCategory2.SidebarCategory, - Channels: []string{channel.Id}, - }, - { - SidebarCategory: channelsCategory2.SidebarCategory, - Channels: []string{}, - }, - }, - opts, - ) - assert.NoError(t, err) - - res2, nErr = ss.Preference().Get(userId, model.PreferenceCategoryFavoriteChannel, channel.Id) - assert.NoError(t, nErr) - assert.NotNil(t, res2) - assert.Equal(t, "true", res2.Value) - - res2, nErr = ss.Preference().Get(userId2, model.PreferenceCategoryFavoriteChannel, channel.Id) - assert.NoError(t, nErr) - assert.NotNil(t, res2) - assert.Equal(t, "true", res2.Value) - - // And then user1 unfavorite it - _, _, err = ss.Channel().UpdateSidebarCategories(userId, team.Id, []*model.SidebarCategoryWithChannels{ - { - SidebarCategory: channelsCategory.SidebarCategory, - Channels: []string{channel.Id}, - }, - { - SidebarCategory: favoritesCategory.SidebarCategory, - Channels: []string{}, - }, - }, - opts, - ) - assert.NoError(t, err) - - res2, nErr = ss.Preference().Get(userId, model.PreferenceCategoryFavoriteChannel, channel.Id) - assert.True(t, errors.Is(nErr, sql.ErrNoRows)) - assert.Nil(t, res2) - - res2, nErr = ss.Preference().Get(userId2, model.PreferenceCategoryFavoriteChannel, channel.Id) - assert.NoError(t, nErr) - assert.NotNil(t, res2) - assert.Equal(t, "true", res2.Value) - - // And finally user2 favorite it - _, _, err = ss.Channel().UpdateSidebarCategories(userId2, team.Id, []*model.SidebarCategoryWithChannels{ - { - SidebarCategory: channelsCategory2.SidebarCategory, - Channels: []string{channel.Id}, - }, - { - SidebarCategory: favoritesCategory2.SidebarCategory, - Channels: []string{}, - }, - }, - opts, - ) - assert.NoError(t, err) - - res2, nErr = ss.Preference().Get(userId, model.PreferenceCategoryFavoriteChannel, channel.Id) - assert.True(t, errors.Is(nErr, sql.ErrNoRows)) - assert.Nil(t, res2) - - res2, nErr = ss.Preference().Get(userId2, model.PreferenceCategoryFavoriteChannel, channel.Id) - assert.True(t, errors.Is(nErr, sql.ErrNoRows)) - assert.Nil(t, res2) - }) - - t.Run("channels removed from Channels or DMs categories should be re-added", func(t *testing.T) { - userId := model.NewId() - team := setupTeam(t, ss, userId) - - // Create some channels - channel, nErr := ss.Channel().Save(&model.Channel{ - Name: "channel", - Type: model.ChannelTypeOpen, - TeamId: team.Id, - }, 10) - require.NoError(t, nErr) - _, err := ss.Channel().SaveMember(&model.ChannelMember{ - UserId: userId, - ChannelId: channel.Id, - NotifyProps: model.GetDefaultChannelNotifyProps(), - }) - require.NoError(t, err) - - otherUserId := model.NewId() - dmChannel, nErr := ss.Channel().SaveDirectChannel( - &model.Channel{ - Name: model.GetDMNameFromIds(userId, otherUserId), - Type: model.ChannelTypeDirect, - }, - &model.ChannelMember{ - UserId: userId, - NotifyProps: model.GetDefaultChannelNotifyProps(), - }, - &model.ChannelMember{ - UserId: otherUserId, - NotifyProps: model.GetDefaultChannelNotifyProps(), - }, - ) - require.NoError(t, nErr) - - opts := &store.SidebarCategorySearchOpts{ - TeamID: team.Id, - ExcludeTeam: false, - AppsCategoryEnabled: true, - } - res, nErr := ss.Channel().CreateInitialSidebarCategories(userId, opts) - require.NoError(t, nErr) - require.NotEmpty(t, res) - - // And some categories - initialCategories, nErr := ss.Channel().GetSidebarCategoriesForTeamForUser(userId, team.Id, opts) - require.NoError(t, nErr) - - channelsCategory := initialCategories.Categories[1] - dmsCategory := initialCategories.Categories[2] - - require.Equal(t, []string{channel.Id}, channelsCategory.Channels) - require.Equal(t, []string{dmChannel.Id}, dmsCategory.Channels) - - // Try to save the categories with no channels in them - categoriesToUpdate := []*model.SidebarCategoryWithChannels{ - { - SidebarCategory: channelsCategory.SidebarCategory, - Channels: []string{}, - }, - { - SidebarCategory: dmsCategory.SidebarCategory, - Channels: []string{}, - }, - } - - updatedCategories, _, nErr := ss.Channel().UpdateSidebarCategories(userId, team.Id, categoriesToUpdate, opts) - assert.NoError(t, nErr) - - // The channels should still exist in the category because they would otherwise be orphaned - assert.Equal(t, []string{channel.Id}, updatedCategories[0].Channels) - assert.Equal(t, []string{dmChannel.Id}, updatedCategories[1].Channels) - }) - - t.Run("should be able to move DMs into and out of custom categories", func(t *testing.T) { - userId := model.NewId() - team := setupTeam(t, ss, userId) - - otherUserId := model.NewId() - dmChannel, nErr := ss.Channel().SaveDirectChannel( - &model.Channel{ - Name: model.GetDMNameFromIds(userId, otherUserId), - Type: model.ChannelTypeDirect, - }, - &model.ChannelMember{ - UserId: userId, - NotifyProps: model.GetDefaultChannelNotifyProps(), - }, - &model.ChannelMember{ - UserId: otherUserId, - NotifyProps: model.GetDefaultChannelNotifyProps(), - }, - ) - require.NoError(t, nErr) - - opts := &store.SidebarCategorySearchOpts{ - TeamID: team.Id, - ExcludeTeam: false, - AppsCategoryEnabled: true, - } - res, nErr := ss.Channel().CreateInitialSidebarCategories(userId, opts) - require.NoError(t, nErr) - require.NotEmpty(t, res) - - // The DM should start in the DMs category - initialCategories, err := ss.Channel().GetSidebarCategoriesForTeamForUser(userId, team.Id, opts) - require.NoError(t, err) - - dmsCategory := initialCategories.Categories[2] - require.Equal(t, []string{dmChannel.Id}, dmsCategory.Channels) - - // Now move the DM into a custom category - customCategory, err := ss.Channel().CreateSidebarCategory(userId, team.Id, &model.SidebarCategoryWithChannels{}, opts) - require.NoError(t, err) - - categoriesToUpdate := []*model.SidebarCategoryWithChannels{ - { - SidebarCategory: dmsCategory.SidebarCategory, - Channels: []string{}, - }, - { - SidebarCategory: customCategory.SidebarCategory, - Channels: []string{dmChannel.Id}, - }, - } - - updatedCategories, _, err := ss.Channel().UpdateSidebarCategories(userId, team.Id, categoriesToUpdate) - assert.NoError(t, err) - assert.Equal(t, dmsCategory.Id, updatedCategories[0].Id) - assert.Equal(t, []string{}, updatedCategories[0].Channels) - assert.Equal(t, customCategory.Id, updatedCategories[1].Id) - assert.Equal(t, []string{dmChannel.Id}, updatedCategories[1].Channels) - - updatedDmsCategory, err := ss.Channel().GetSidebarCategory(dmsCategory.Id, opts) - require.NoError(t, err) - assert.Equal(t, []string{}, updatedDmsCategory.Channels) - - updatedCustomCategory, err := ss.Channel().GetSidebarCategory(customCategory.Id, opts) - require.NoError(t, err) - assert.Equal(t, []string{dmChannel.Id}, updatedCustomCategory.Channels) - - // And move it back out of the custom category - categoriesToUpdate = []*model.SidebarCategoryWithChannels{ - { - SidebarCategory: dmsCategory.SidebarCategory, - Channels: []string{dmChannel.Id}, - }, - { - SidebarCategory: customCategory.SidebarCategory, - Channels: []string{}, - }, - } - - updatedCategories, _, err = ss.Channel().UpdateSidebarCategories(userId, team.Id, categoriesToUpdate, opts) - assert.NoError(t, err) - assert.Equal(t, dmsCategory.Id, updatedCategories[0].Id) - assert.Equal(t, []string{dmChannel.Id}, updatedCategories[0].Channels) - assert.Equal(t, customCategory.Id, updatedCategories[1].Id) - assert.Equal(t, []string{}, updatedCategories[1].Channels) - - updatedDmsCategory, err = ss.Channel().GetSidebarCategory(dmsCategory.Id, opts) - require.NoError(t, err) - assert.Equal(t, []string{dmChannel.Id}, updatedDmsCategory.Channels) - - updatedCustomCategory, err = ss.Channel().GetSidebarCategory(customCategory.Id, opts) - require.NoError(t, err) - assert.Equal(t, []string{}, updatedCustomCategory.Channels) - }) - - t.Run("should successfully move channels between categories", func(t *testing.T) { - userId := model.NewId() - team := setupTeam(t, ss, userId) - - // Join a channel - channel, nErr := ss.Channel().Save(&model.Channel{ - Name: "channel", - Type: model.ChannelTypeOpen, - TeamId: team.Id, - }, 10) - require.NoError(t, nErr) - _, err := ss.Channel().SaveMember(&model.ChannelMember{ - UserId: userId, - ChannelId: channel.Id, - NotifyProps: model.GetDefaultChannelNotifyProps(), - }) - require.NoError(t, err) - - // And then create the initial categories so that it includes the channel - opts := &store.SidebarCategorySearchOpts{ - TeamID: team.Id, - ExcludeTeam: false, - AppsCategoryEnabled: true, - } - res, nErr := ss.Channel().CreateInitialSidebarCategories(userId, opts) - require.NoError(t, nErr) - require.NotEmpty(t, res) - - initialCategories, nErr := ss.Channel().GetSidebarCategoriesForTeamForUser(userId, team.Id, opts) - require.NoError(t, nErr) - - channelsCategory := initialCategories.Categories[1] - require.Equal(t, []string{channel.Id}, channelsCategory.Channels) - - customCategory, nErr := ss.Channel().CreateSidebarCategory(userId, team.Id, &model.SidebarCategoryWithChannels{}, opts) - require.NoError(t, nErr) - - // Move the channel one way - updatedCategories, _, nErr := ss.Channel().UpdateSidebarCategories(userId, team.Id, []*model.SidebarCategoryWithChannels{ - { - SidebarCategory: channelsCategory.SidebarCategory, - Channels: []string{}, - }, - { - SidebarCategory: customCategory.SidebarCategory, - Channels: []string{channel.Id}, - }, - }, - opts, - ) - assert.NoError(t, nErr) - - assert.Equal(t, []string{}, updatedCategories[0].Channels) - assert.Equal(t, []string{channel.Id}, updatedCategories[1].Channels) - - // And then the other - updatedCategories, _, nErr = ss.Channel().UpdateSidebarCategories(userId, team.Id, []*model.SidebarCategoryWithChannels{ - { - SidebarCategory: channelsCategory.SidebarCategory, - Channels: []string{channel.Id}, - }, - { - SidebarCategory: customCategory.SidebarCategory, - Channels: []string{}, - }, - }, - opts, - ) - assert.NoError(t, nErr) - assert.Equal(t, []string{channel.Id}, updatedCategories[0].Channels) - assert.Equal(t, []string{}, updatedCategories[1].Channels) - }) - - t.Run("should correctly return the original categories that were modified", func(t *testing.T) { - userId := model.NewId() - team := setupTeam(t, ss, userId) - - // Join a channel - channel, nErr := ss.Channel().Save(&model.Channel{ - Name: "channel", - Type: model.ChannelTypeOpen, - TeamId: team.Id, - }, 10) - require.NoError(t, nErr) - _, err := ss.Channel().SaveMember(&model.ChannelMember{ - UserId: userId, - ChannelId: channel.Id, - NotifyProps: model.GetDefaultChannelNotifyProps(), - }) - require.NoError(t, err) - - // And then create the initial categories so that Channels includes the channel - opts := &store.SidebarCategorySearchOpts{ - TeamID: team.Id, - ExcludeTeam: false, - AppsCategoryEnabled: true, - } - res, nErr := ss.Channel().CreateInitialSidebarCategories(userId, opts) - require.NoError(t, nErr) - require.NotEmpty(t, res) - - initialCategories, nErr := ss.Channel().GetSidebarCategoriesForTeamForUser(userId, team.Id, opts) - require.NoError(t, nErr) - - channelsCategory := initialCategories.Categories[1] - require.Equal(t, []string{channel.Id}, channelsCategory.Channels) - - customCategory, nErr := ss.Channel().CreateSidebarCategory(userId, team.Id, &model.SidebarCategoryWithChannels{ - SidebarCategory: model.SidebarCategory{ - DisplayName: "originalName", - }, - }, - opts, - ) - require.NoError(t, nErr) - - // Rename the custom category - updatedCategories, originalCategories, nErr := ss.Channel().UpdateSidebarCategories(userId, team.Id, []*model.SidebarCategoryWithChannels{ - { - SidebarCategory: model.SidebarCategory{ - Id: customCategory.Id, - DisplayName: "updatedName", - }, - }, - }, - opts, - ) - require.NoError(t, nErr) - require.Equal(t, len(updatedCategories), len(originalCategories)) - assert.Equal(t, "originalName", originalCategories[0].DisplayName) - assert.Equal(t, "updatedName", updatedCategories[0].DisplayName) - - // Move a channel - updatedCategories, originalCategories, nErr = ss.Channel().UpdateSidebarCategories(userId, team.Id, []*model.SidebarCategoryWithChannels{ - { - SidebarCategory: channelsCategory.SidebarCategory, - Channels: []string{}, - }, - { - SidebarCategory: customCategory.SidebarCategory, - Channels: []string{channel.Id}, - }, - }, - opts, - ) - require.NoError(t, nErr) - require.Equal(t, len(updatedCategories), len(originalCategories)) - require.Equal(t, updatedCategories[0].Id, originalCategories[0].Id) - require.Equal(t, updatedCategories[1].Id, originalCategories[1].Id) - - assert.Equal(t, []string{channel.Id}, originalCategories[0].Channels) - assert.Equal(t, []string{}, updatedCategories[0].Channels) - assert.Equal(t, []string{}, originalCategories[1].Channels) - assert.Equal(t, []string{channel.Id}, updatedCategories[1].Channels) - }) -} - -func setupInitialSidebarCategoriesWithAppsCategory(t *testing.T, ss store.Store) (string, string) { - userId := model.NewId() - team := setupTeam(t, ss, userId) - - opts := &store.SidebarCategorySearchOpts{ - TeamID: team.Id, - ExcludeTeam: false, - AppsCategoryEnabled: true, - } - res, nErr := ss.Channel().CreateInitialSidebarCategories(userId, opts) - require.NoError(t, nErr) - require.NotEmpty(t, res) - - res, err := ss.Channel().GetSidebarCategoriesForTeamForUser(userId, team.Id, opts) - require.NoError(t, err) - require.Len(t, res.Categories, 4) - - return userId, team.Id -} - -func testClearSidebarOnTeamLeaveWithAppsCategory(t *testing.T, ss store.Store, s SqlStore) { - t.Run("should delete all sidebar categories and channels on the team", func(t *testing.T) { - userId, teamId := setupInitialSidebarCategoriesWithAppsCategory(t, ss) - - user := &model.User{ - Id: userId, - } - - // Create some channels and assign them to a custom category - channel1, nErr := ss.Channel().Save(&model.Channel{ - Name: model.NewId(), - TeamId: teamId, - Type: model.ChannelTypeOpen, - }, 1000) - require.NoError(t, nErr) - - dmChannel1, nErr := ss.Channel().CreateDirectChannel(user, &model.User{ - Id: model.NewId(), - }) - require.NoError(t, nErr) - - opts := &store.SidebarCategorySearchOpts{ - AppsCategoryEnabled: true, - } - - _, err := ss.Channel().CreateSidebarCategory(userId, teamId, &model.SidebarCategoryWithChannels{ - Channels: []string{channel1.Id, dmChannel1.Id}, - }, - opts, - ) - require.NoError(t, err) - - // Confirm that we start with the right number of categories and SidebarChannels entries - var count int64 - err = s.GetMasterX().Get(&count, "SELECT COUNT(*) FROM SidebarCategories WHERE UserId = ?", userId) - require.NoError(t, err) - require.Equal(t, int64(5), count) - - err = s.GetMasterX().Get(&count, "SELECT COUNT(*) FROM SidebarChannels WHERE UserId = ?", userId) - require.NoError(t, err) - require.Equal(t, int64(2), count) - - // Leave the team - err = ss.Channel().ClearSidebarOnTeamLeave(userId, teamId) - assert.NoError(t, err) - - // Confirm that all the categories and SidebarChannel entries have been deleted - err = s.GetMasterX().Get(&count, "SELECT COUNT(*) FROM SidebarCategories WHERE UserId = ?", userId) - require.NoError(t, err) - assert.Equal(t, int64(0), count) - - err = s.GetMasterX().Get(&count, "SELECT COUNT(*) FROM SidebarChannels WHERE UserId = ?", userId) - require.NoError(t, err) - assert.Equal(t, int64(0), count) - }) - - t.Run("should not delete sidebar categories and channels on another the team", func(t *testing.T) { - userId, teamId := setupInitialSidebarCategoriesWithAppsCategory(t, ss) - - user := &model.User{ - Id: userId, - } - - // Create some channels and assign them to a custom category - channel1, nErr := ss.Channel().Save(&model.Channel{ - Name: model.NewId(), - TeamId: teamId, - Type: model.ChannelTypeOpen, - }, 1000) - require.NoError(t, nErr) - - dmChannel1, nErr := ss.Channel().CreateDirectChannel(user, &model.User{ - Id: model.NewId(), - }) - require.NoError(t, nErr) - - opts := &store.SidebarCategorySearchOpts{ - AppsCategoryEnabled: true, - } - - _, err := ss.Channel().CreateSidebarCategory(userId, teamId, &model.SidebarCategoryWithChannels{ - Channels: []string{channel1.Id, dmChannel1.Id}, - }, - opts, - ) - require.NoError(t, err) - - // Confirm that we start with the right number of categories and SidebarChannels entries - var count int64 - err = s.GetMasterX().Get(&count, "SELECT COUNT(*) FROM SidebarCategories WHERE UserId = ?", userId) - require.NoError(t, err) - require.Equal(t, int64(5), count) - - err = s.GetMasterX().Get(&count, "SELECT COUNT(*) FROM SidebarChannels WHERE UserId = ?", userId) - require.NoError(t, err) - require.Equal(t, int64(2), count) - - // Leave another team - err = ss.Channel().ClearSidebarOnTeamLeave(userId, model.NewId()) - assert.NoError(t, err) - - // Confirm that nothing has been deleted - err = s.GetMasterX().Get(&count, "SELECT COUNT(*) FROM SidebarCategories WHERE UserId = ?", userId) - require.NoError(t, err) - assert.Equal(t, int64(5), count) - - err = s.GetMasterX().Get(&count, "SELECT COUNT(*) FROM SidebarChannels WHERE UserId = ?", userId) - require.NoError(t, err) - assert.Equal(t, int64(2), count) - }) - - t.Run("MM-30314 should not delete channels on another team under specific circumstances", func(t *testing.T) { - userId, teamId := setupInitialSidebarCategoriesWithAppsCategory(t, ss) - - user := &model.User{ - Id: userId, - } - user2 := &model.User{ - Id: model.NewId(), - } - - // Create a second team and set up the sidebar categories for it - team2 := setupTeam(t, ss, userId) - - opts := &store.SidebarCategorySearchOpts{ - TeamID: team2.Id, - ExcludeTeam: false, - AppsCategoryEnabled: true, - } - res, err := ss.Channel().CreateInitialSidebarCategories(userId, opts) - require.NoError(t, err) - require.NotEmpty(t, res) - - res, err = ss.Channel().GetSidebarCategoriesForTeamForUser(userId, team2.Id, opts) - require.NoError(t, err) - require.Len(t, res.Categories, 4) - - // On the first team, create some channels and assign them to a custom category - channel1, nErr := ss.Channel().Save(&model.Channel{ - Name: model.NewId(), - TeamId: teamId, - Type: model.ChannelTypeOpen, - }, 1000) - require.NoError(t, nErr) - - dmChannel1, nErr := ss.Channel().CreateDirectChannel(user, user2) - require.NoError(t, nErr) - - _, err = ss.Channel().CreateSidebarCategory(userId, teamId, &model.SidebarCategoryWithChannels{ - Channels: []string{channel1.Id, dmChannel1.Id}, - }, - opts, - ) - require.NoError(t, err) - - // Do the same on the second team - channel2, nErr := ss.Channel().Save(&model.Channel{ - Name: model.NewId(), - TeamId: team2.Id, - Type: model.ChannelTypeOpen, - }, 1000) - require.NoError(t, nErr) - - _, err = ss.Channel().CreateSidebarCategory(userId, team2.Id, &model.SidebarCategoryWithChannels{ - Channels: []string{channel2.Id, dmChannel1.Id}, - }, - opts, - ) - require.NoError(t, err) - - // Confirm that we start with the right number of categories and SidebarChannels entries - var count int64 - err = s.GetMasterX().Get(&count, "SELECT COUNT(*) FROM SidebarCategories WHERE UserId = ?", userId) - require.NoError(t, err) - require.Equal(t, int64(10), count) - - err = s.GetMasterX().Get(&count, "SELECT COUNT(*) FROM SidebarChannels WHERE UserId = ?", userId) - require.NoError(t, err) - require.Equal(t, int64(4), count) - - // Leave the first team - err = ss.Channel().ClearSidebarOnTeamLeave(userId, teamId) - assert.NoError(t, err) - - // Confirm that we have the correct number of categories and SidebarChannels entries left over - err = s.GetMasterX().Get(&count, "SELECT COUNT(*) FROM SidebarCategories WHERE UserId = ?", userId) - require.NoError(t, err) - assert.Equal(t, int64(5), count) - - err = s.GetMasterX().Get(&count, "SELECT COUNT(*) FROM SidebarChannels WHERE UserId = ?", userId) - require.NoError(t, err) - assert.Equal(t, int64(2), count) - - // Confirm that the categories on the second team are unchanged - res, err = ss.Channel().GetSidebarCategoriesForTeamForUser(userId, team2.Id, &store.SidebarCategorySearchOpts{ - AppsCategoryEnabled: true, - }) - require.NoError(t, err) - assert.Len(t, res.Categories, 5) - - assert.Equal(t, model.SidebarCategoryCustom, res.Categories[1].Type) - assert.Equal(t, []string{channel2.Id, dmChannel1.Id}, res.Categories[1].Channels) - }) -} - -func testDeleteSidebarCategoryWithAppsCategory(t *testing.T, ss store.Store, s SqlStore) { - t.Run("should correctly remove an empty category", func(t *testing.T) { - userId, teamId := setupInitialSidebarCategoriesWithAppsCategory(t, ss) - defer ss.User().PermanentDelete(userId) - - opts := &store.SidebarCategorySearchOpts{ - AppsCategoryEnabled: true, - } - - newCategory, err := ss.Channel().CreateSidebarCategory(userId, teamId, &model.SidebarCategoryWithChannels{}, opts) - require.NoError(t, err) - require.NotNil(t, newCategory) - - // Ensure that the category was created properly - res, err := ss.Channel().GetSidebarCategoriesForTeamForUser(userId, teamId, opts) - require.NoError(t, err) - require.Len(t, res.Categories, 5) - - // Then delete it and confirm that was done correctly - err = ss.Channel().DeleteSidebarCategory(newCategory.Id) - assert.NoError(t, err) - - res, err = ss.Channel().GetSidebarCategoriesForTeamForUser(userId, teamId, opts) - require.NoError(t, err) - require.Len(t, res.Categories, 4) - }) - - t.Run("should correctly remove a category and its channels", func(t *testing.T) { - userId, teamId := setupInitialSidebarCategoriesWithAppsCategory(t, ss) - defer ss.User().PermanentDelete(userId) - - opts := &store.SidebarCategorySearchOpts{ - AppsCategoryEnabled: true, - } - - user := &model.User{ - Id: userId, - } - - // Create some channels - channel1, nErr := ss.Channel().Save(&model.Channel{ - Name: model.NewId(), - TeamId: teamId, - Type: model.ChannelTypeOpen, - }, 1000) - require.NoError(t, nErr) - defer ss.Channel().PermanentDelete(channel1.Id) - - channel2, nErr := ss.Channel().Save(&model.Channel{ - Name: model.NewId(), - TeamId: teamId, - Type: model.ChannelTypePrivate, - }, 1000) - require.NoError(t, nErr) - defer ss.Channel().PermanentDelete(channel2.Id) - - dmChannel1, nErr := ss.Channel().CreateDirectChannel(user, &model.User{ - Id: model.NewId(), - }) - require.NoError(t, nErr) - defer ss.Channel().PermanentDelete(dmChannel1.Id) - - // Assign some of those channels to a custom category - newCategory, err := ss.Channel().CreateSidebarCategory(userId, teamId, &model.SidebarCategoryWithChannels{ - Channels: []string{channel1.Id, channel2.Id, dmChannel1.Id}, - }, - opts, - ) - require.NoError(t, err) - require.NotNil(t, newCategory) - - // Ensure that the categories are set up correctly - res, err := ss.Channel().GetSidebarCategoriesForTeamForUser(userId, teamId, opts) - require.NoError(t, err) - require.Len(t, res.Categories, 5) - - require.Equal(t, model.SidebarCategoryCustom, res.Categories[1].Type) - require.Equal(t, []string{channel1.Id, channel2.Id, dmChannel1.Id}, res.Categories[1].Channels) - - // Actually delete the channel - err = ss.Channel().DeleteSidebarCategory(newCategory.Id) - assert.NoError(t, err) - - // Confirm that the category was deleted... - res, err = ss.Channel().GetSidebarCategoriesForTeamForUser(userId, teamId, opts) - assert.NoError(t, err) - assert.Len(t, res.Categories, 4) - - // ...and that the corresponding SidebarChannel entries were deleted - var count int64 - countErr := s.GetMasterX().Get(&count, ` - SELECT - COUNT(*) - FROM - SidebarChannels - WHERE - CategoryId = ?`, newCategory.Id) - require.NoError(t, countErr) - assert.Equal(t, int64(0), count) - }) - - t.Run("should not allow you to remove non-custom categories", func(t *testing.T) { - userId, teamId := setupInitialSidebarCategoriesWithAppsCategory(t, ss) - defer ss.User().PermanentDelete(userId) - res, err := ss.Channel().GetSidebarCategoriesForTeamForUser(userId, teamId, &store.SidebarCategorySearchOpts{ - AppsCategoryEnabled: true, - }) - require.NoError(t, err) - require.Len(t, res.Categories, 4) - require.Equal(t, model.SidebarCategoryFavorites, res.Categories[0].Type) - require.Equal(t, model.SidebarCategoryChannels, res.Categories[1].Type) - require.Equal(t, model.SidebarCategoryDirectMessages, res.Categories[2].Type) - require.Equal(t, model.SidebarCategoryApps, res.Categories[3].Type) - - err = ss.Channel().DeleteSidebarCategory(res.Categories[0].Id) - assert.Error(t, err) - - err = ss.Channel().DeleteSidebarCategory(res.Categories[1].Id) - assert.Error(t, err) - - err = ss.Channel().DeleteSidebarCategory(res.Categories[2].Id) - assert.Error(t, err) - - err = ss.Channel().DeleteSidebarCategory(res.Categories[3].Id) - assert.Error(t, err) - }) -} - -func testUpdateSidebarChannelsByPreferencesWithAppsCategory(t *testing.T, ss store.Store) { - t.Run("Should be able to update sidebar channels", func(t *testing.T) { - userId := model.NewId() - teamId := model.NewId() - - opts := &store.SidebarCategorySearchOpts{ - TeamID: teamId, - ExcludeTeam: false, - AppsCategoryEnabled: true, - } - res, nErr := ss.Channel().CreateInitialSidebarCategories(userId, opts) - require.NoError(t, nErr) - require.NotEmpty(t, res) - - channel, nErr := ss.Channel().Save(&model.Channel{ - Name: "channel", - Type: model.ChannelTypeOpen, - TeamId: teamId, - }, 10) - require.NoError(t, nErr) - - err := ss.Channel().UpdateSidebarChannelsByPreferences(model.Preferences{ - model.Preference{ - Name: channel.Id, - Category: model.PreferenceCategoryFavoriteChannel, - Value: "true", - }, - }) - assert.NoError(t, err) - }) - - t.Run("Should not panic if channel is not found", func(t *testing.T) { - userId := model.NewId() - teamId := model.NewId() - - opts := &store.SidebarCategorySearchOpts{ - TeamID: teamId, - ExcludeTeam: false, - AppsCategoryEnabled: true, - } - res, nErr := ss.Channel().CreateInitialSidebarCategories(userId, opts) - assert.NoError(t, nErr) - require.NotEmpty(t, res) - - require.NotPanics(t, func() { - _ = ss.Channel().UpdateSidebarChannelsByPreferences(model.Preferences{ - model.Preference{ - Name: "fakeid", - Category: model.PreferenceCategoryFavoriteChannel, - Value: "true", - }, - }) - }) - }) -} - -func testSidebarCategoryDeadlockWithAppsCategory(t *testing.T, ss store.Store) { - userID := model.NewId() - team := setupTeam(t, ss, userID) - - // Join a channel - channel, err := ss.Channel().Save(&model.Channel{ - Name: "channel", - Type: model.ChannelTypeOpen, - TeamId: team.Id, - }, 10) - require.NoError(t, err) - _, err = ss.Channel().SaveMember(&model.ChannelMember{ - UserId: userID, - ChannelId: channel.Id, - NotifyProps: model.GetDefaultChannelNotifyProps(), - }) - require.NoError(t, err) - - // And then create the initial categories so that it includes the channel - opts := &store.SidebarCategorySearchOpts{ - TeamID: team.Id, - ExcludeTeam: false, - AppsCategoryEnabled: true, - } - res, err := ss.Channel().CreateInitialSidebarCategories(userID, opts) - require.NoError(t, err) - require.NotEmpty(t, res) - - initialCategories, err := ss.Channel().GetSidebarCategoriesForTeamForUser(userID, team.Id, opts) - require.NoError(t, err) - - channelsCategory := initialCategories.Categories[1] - require.Equal(t, []string{channel.Id}, channelsCategory.Channels) - - customCategory, err := ss.Channel().CreateSidebarCategory(userID, team.Id, &model.SidebarCategoryWithChannels{}, opts) - require.NoError(t, err) - - var wg sync.WaitGroup - wg.Add(2) - - go func() { - defer wg.Done() - _, _, err := ss.Channel().UpdateSidebarCategories(userID, team.Id, []*model.SidebarCategoryWithChannels{ - { - SidebarCategory: channelsCategory.SidebarCategory, - Channels: []string{}, - }, - { - SidebarCategory: customCategory.SidebarCategory, - Channels: []string{channel.Id}, - }, - }) - if err != nil { - var nfErr *store.ErrNotFound - require.True(t, errors.As(err, &nfErr)) - } - }() - - go func() { - defer wg.Done() - err := ss.Channel().DeleteSidebarCategory(customCategory.Id) - require.NoError(t, err) - }() - - wg.Wait() -} diff --git a/server/channels/store/storetest/mocks/ChannelStore.go b/server/channels/store/storetest/mocks/ChannelStore.go index fc1e9eed2b..48ee4b9297 100644 --- a/server/channels/store/storetest/mocks/ChannelStore.go +++ b/server/channels/store/storetest/mocks/ChannelStore.go @@ -298,32 +298,25 @@ func (_m *ChannelStore) CreateInitialSidebarCategories(userID string, opts *stor return r0, r1 } -// CreateSidebarCategory provides a mock function with given fields: userID, teamID, newCategory, options -func (_m *ChannelStore) CreateSidebarCategory(userID string, teamID string, newCategory *model.SidebarCategoryWithChannels, options ...*store.SidebarCategorySearchOpts) (*model.SidebarCategoryWithChannels, error) { - _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...) +// CreateSidebarCategory provides a mock function with given fields: userID, teamID, newCategory +func (_m *ChannelStore) CreateSidebarCategory(userID string, teamID string, newCategory *model.SidebarCategoryWithChannels) (*model.SidebarCategoryWithChannels, error) { + ret := _m.Called(userID, teamID, newCategory) var r0 *model.SidebarCategoryWithChannels var r1 error - if rf, ok := ret.Get(0).(func(string, string, *model.SidebarCategoryWithChannels, ...*store.SidebarCategorySearchOpts) (*model.SidebarCategoryWithChannels, error)); ok { - return rf(userID, teamID, newCategory, options...) + if rf, ok := ret.Get(0).(func(string, string, *model.SidebarCategoryWithChannels) (*model.SidebarCategoryWithChannels, error)); ok { + return rf(userID, teamID, newCategory) } - if rf, ok := ret.Get(0).(func(string, string, *model.SidebarCategoryWithChannels, ...*store.SidebarCategorySearchOpts) *model.SidebarCategoryWithChannels); ok { - r0 = rf(userID, teamID, newCategory, options...) + if rf, ok := ret.Get(0).(func(string, string, *model.SidebarCategoryWithChannels) *model.SidebarCategoryWithChannels); ok { + r0 = rf(userID, teamID, newCategory) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*model.SidebarCategoryWithChannels) } } - if rf, ok := ret.Get(1).(func(string, string, *model.SidebarCategoryWithChannels, ...*store.SidebarCategorySearchOpts) error); ok { - r1 = rf(userID, teamID, newCategory, options...) + if rf, ok := ret.Get(1).(func(string, string, *model.SidebarCategoryWithChannels) error); ok { + r1 = rf(userID, teamID, newCategory) } else { r1 = ret.Error(1) } @@ -605,32 +598,6 @@ func (_m *ChannelStore) GetAllDirectChannelsForExportAfter(limit int, afterID st 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 func (_m *ChannelStore) GetByName(team_id string, name string, allowFromCache bool) (*model.Channel, error) { ret := _m.Called(team_id, name, allowFromCache) @@ -1625,32 +1592,25 @@ func (_m *ChannelStore) GetSidebarCategories(userID string, opts *store.SidebarC return r0, r1 } -// GetSidebarCategoriesForTeamForUser provides a mock function with given fields: userID, teamID, options -func (_m *ChannelStore) GetSidebarCategoriesForTeamForUser(userID string, teamID string, options ...*store.SidebarCategorySearchOpts) (*model.OrderedSidebarCategories, error) { - _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...) +// GetSidebarCategoriesForTeamForUser provides a mock function with given fields: userID, teamID +func (_m *ChannelStore) GetSidebarCategoriesForTeamForUser(userID string, teamID string) (*model.OrderedSidebarCategories, error) { + ret := _m.Called(userID, teamID) var r0 *model.OrderedSidebarCategories var r1 error - if rf, ok := ret.Get(0).(func(string, string, ...*store.SidebarCategorySearchOpts) (*model.OrderedSidebarCategories, error)); ok { - return rf(userID, teamID, options...) + if rf, ok := ret.Get(0).(func(string, string) (*model.OrderedSidebarCategories, error)); ok { + return rf(userID, teamID) } - if rf, ok := ret.Get(0).(func(string, string, ...*store.SidebarCategorySearchOpts) *model.OrderedSidebarCategories); ok { - r0 = rf(userID, teamID, options...) + if rf, ok := ret.Get(0).(func(string, string) *model.OrderedSidebarCategories); ok { + r0 = rf(userID, teamID) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*model.OrderedSidebarCategories) } } - if rf, ok := ret.Get(1).(func(string, string, ...*store.SidebarCategorySearchOpts) error); ok { - r1 = rf(userID, teamID, options...) + if rf, ok := ret.Get(1).(func(string, string) error); ok { + r1 = rf(userID, teamID) } else { r1 = ret.Error(1) } @@ -1658,32 +1618,25 @@ func (_m *ChannelStore) GetSidebarCategoriesForTeamForUser(userID string, teamID return r0, r1 } -// GetSidebarCategory provides a mock function with given fields: categoryID, options -func (_m *ChannelStore) GetSidebarCategory(categoryID string, options ...*store.SidebarCategorySearchOpts) (*model.SidebarCategoryWithChannels, error) { - _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...) +// GetSidebarCategory provides a mock function with given fields: categoryID +func (_m *ChannelStore) GetSidebarCategory(categoryID string) (*model.SidebarCategoryWithChannels, error) { + ret := _m.Called(categoryID) var r0 *model.SidebarCategoryWithChannels var r1 error - if rf, ok := ret.Get(0).(func(string, ...*store.SidebarCategorySearchOpts) (*model.SidebarCategoryWithChannels, error)); ok { - return rf(categoryID, options...) + if rf, ok := ret.Get(0).(func(string) (*model.SidebarCategoryWithChannels, error)); ok { + return rf(categoryID) } - if rf, ok := ret.Get(0).(func(string, ...*store.SidebarCategorySearchOpts) *model.SidebarCategoryWithChannels); ok { - r0 = rf(categoryID, options...) + if rf, ok := ret.Get(0).(func(string) *model.SidebarCategoryWithChannels); ok { + r0 = rf(categoryID) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*model.SidebarCategoryWithChannels) } } - if rf, ok := ret.Get(1).(func(string, ...*store.SidebarCategorySearchOpts) error); ok { - r1 = rf(categoryID, options...) + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(categoryID) } else { r1 = ret.Error(1) } @@ -2629,41 +2582,34 @@ func (_m *ChannelStore) UpdateMultipleMembers(members []*model.ChannelMember) ([ return r0, r1 } -// UpdateSidebarCategories provides a mock function with given fields: userID, teamID, categories, options -func (_m *ChannelStore) UpdateSidebarCategories(userID string, teamID string, categories []*model.SidebarCategoryWithChannels, options ...*store.SidebarCategorySearchOpts) ([]*model.SidebarCategoryWithChannels, []*model.SidebarCategoryWithChannels, error) { - _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...) +// UpdateSidebarCategories provides a mock function with given fields: userID, teamID, categories +func (_m *ChannelStore) UpdateSidebarCategories(userID string, teamID string, categories []*model.SidebarCategoryWithChannels) ([]*model.SidebarCategoryWithChannels, []*model.SidebarCategoryWithChannels, error) { + ret := _m.Called(userID, teamID, categories) var r0 []*model.SidebarCategoryWithChannels var r1 []*model.SidebarCategoryWithChannels var r2 error - if rf, ok := ret.Get(0).(func(string, string, []*model.SidebarCategoryWithChannels, ...*store.SidebarCategorySearchOpts) ([]*model.SidebarCategoryWithChannels, []*model.SidebarCategoryWithChannels, error)); ok { - return rf(userID, teamID, categories, options...) + if rf, ok := ret.Get(0).(func(string, string, []*model.SidebarCategoryWithChannels) ([]*model.SidebarCategoryWithChannels, []*model.SidebarCategoryWithChannels, error)); ok { + return rf(userID, teamID, categories) } - if rf, ok := ret.Get(0).(func(string, string, []*model.SidebarCategoryWithChannels, ...*store.SidebarCategorySearchOpts) []*model.SidebarCategoryWithChannels); ok { - r0 = rf(userID, teamID, categories, options...) + if rf, ok := ret.Get(0).(func(string, string, []*model.SidebarCategoryWithChannels) []*model.SidebarCategoryWithChannels); ok { + r0 = rf(userID, teamID, categories) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]*model.SidebarCategoryWithChannels) } } - if rf, ok := ret.Get(1).(func(string, string, []*model.SidebarCategoryWithChannels, ...*store.SidebarCategorySearchOpts) []*model.SidebarCategoryWithChannels); ok { - r1 = rf(userID, teamID, categories, options...) + if rf, ok := ret.Get(1).(func(string, string, []*model.SidebarCategoryWithChannels) []*model.SidebarCategoryWithChannels); ok { + r1 = rf(userID, teamID, categories) } else { if ret.Get(1) != nil { r1 = ret.Get(1).([]*model.SidebarCategoryWithChannels) } } - if rf, ok := ret.Get(2).(func(string, string, []*model.SidebarCategoryWithChannels, ...*store.SidebarCategorySearchOpts) error); ok { - r2 = rf(userID, teamID, categories, options...) + if rf, ok := ret.Get(2).(func(string, string, []*model.SidebarCategoryWithChannels) error); ok { + r2 = rf(userID, teamID, categories) } else { r2 = ret.Error(2) } diff --git a/server/channels/store/timerlayer/timerlayer.go b/server/channels/store/timerlayer/timerlayer.go index 7ae4829b89..519f0d5962 100644 --- a/server/channels/store/timerlayer/timerlayer.go +++ b/server/channels/store/timerlayer/timerlayer.go @@ -784,10 +784,10 @@ func (s *TimerLayerChannelStore) CreateInitialSidebarCategories(userID string, o return result, err } -func (s *TimerLayerChannelStore) CreateSidebarCategory(userID string, teamID string, newCategory *model.SidebarCategoryWithChannels, options ...*store.SidebarCategorySearchOpts) (*model.SidebarCategoryWithChannels, error) { +func (s *TimerLayerChannelStore) CreateSidebarCategory(userID string, teamID string, newCategory *model.SidebarCategoryWithChannels) (*model.SidebarCategoryWithChannels, error) { start := time.Now() - result, err := s.ChannelStore.CreateSidebarCategory(userID, teamID, newCategory, options...) + result, err := s.ChannelStore.CreateSidebarCategory(userID, teamID, newCategory) elapsed := float64(time.Since(start)) / float64(time.Second) if s.Root.Metrics != nil { @@ -992,22 +992,6 @@ func (s *TimerLayerChannelStore) GetAllDirectChannelsForExportAfter(limit int, a 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) { start := time.Now() @@ -1632,10 +1616,10 @@ func (s *TimerLayerChannelStore) GetSidebarCategories(userID string, opts *store return result, err } -func (s *TimerLayerChannelStore) GetSidebarCategoriesForTeamForUser(userID string, teamID string, options ...*store.SidebarCategorySearchOpts) (*model.OrderedSidebarCategories, error) { +func (s *TimerLayerChannelStore) GetSidebarCategoriesForTeamForUser(userID string, teamID string) (*model.OrderedSidebarCategories, error) { start := time.Now() - result, err := s.ChannelStore.GetSidebarCategoriesForTeamForUser(userID, teamID, options...) + result, err := s.ChannelStore.GetSidebarCategoriesForTeamForUser(userID, teamID) elapsed := float64(time.Since(start)) / float64(time.Second) if s.Root.Metrics != nil { @@ -1648,10 +1632,10 @@ func (s *TimerLayerChannelStore) GetSidebarCategoriesForTeamForUser(userID strin return result, err } -func (s *TimerLayerChannelStore) GetSidebarCategory(categoryID string, options ...*store.SidebarCategorySearchOpts) (*model.SidebarCategoryWithChannels, error) { +func (s *TimerLayerChannelStore) GetSidebarCategory(categoryID string) (*model.SidebarCategoryWithChannels, error) { start := time.Now() - result, err := s.ChannelStore.GetSidebarCategory(categoryID, options...) + result, err := s.ChannelStore.GetSidebarCategory(categoryID) elapsed := float64(time.Since(start)) / float64(time.Second) if s.Root.Metrics != nil { @@ -2425,10 +2409,10 @@ func (s *TimerLayerChannelStore) UpdateMultipleMembers(members []*model.ChannelM return result, err } -func (s *TimerLayerChannelStore) UpdateSidebarCategories(userID string, teamID string, categories []*model.SidebarCategoryWithChannels, options ...*store.SidebarCategorySearchOpts) ([]*model.SidebarCategoryWithChannels, []*model.SidebarCategoryWithChannels, error) { +func (s *TimerLayerChannelStore) UpdateSidebarCategories(userID string, teamID string, categories []*model.SidebarCategoryWithChannels) ([]*model.SidebarCategoryWithChannels, []*model.SidebarCategoryWithChannels, error) { start := time.Now() - result, resultVar1, err := s.ChannelStore.UpdateSidebarCategories(userID, teamID, categories, options...) + result, resultVar1, err := s.ChannelStore.UpdateSidebarCategories(userID, teamID, categories) elapsed := float64(time.Since(start)) / float64(time.Second) if s.Root.Metrics != nil { diff --git a/server/public/model/channel_sidebar.go b/server/public/model/channel_sidebar.go index 2e2c3612c1..e8b5a6a215 100644 --- a/server/public/model/channel_sidebar.go +++ b/server/public/model/channel_sidebar.go @@ -13,12 +13,11 @@ type SidebarCategoryType string type SidebarCategorySorting string const ( - // Each sidebar category has a 'type'. System categories are Channels, Favorites, DMs and Apps + // Each sidebar category has a 'type'. System categories are Channels, Favorites and DMs // All user-created categories will have type Custom SidebarCategoryChannels SidebarCategoryType = "channels" SidebarCategoryDirectMessages SidebarCategoryType = "direct_messages" SidebarCategoryFavorites SidebarCategoryType = "favorites" - SidebarCategoryApps SidebarCategoryType = "apps" SidebarCategoryCustom SidebarCategoryType = "custom" // Increment to use when adding/reordering things in the sidebar MinimalSidebarSortDistance = 10 @@ -26,7 +25,6 @@ const ( DefaultSidebarSortOrderFavorites = 0 DefaultSidebarSortOrderChannels = DefaultSidebarSortOrderFavorites + MinimalSidebarSortDistance DefaultSidebarSortOrderDMs = DefaultSidebarSortOrderChannels + MinimalSidebarSortDistance - DefaultSidebarSortOrderApps = DefaultSidebarSortOrderDMs + MinimalSidebarSortDistance // Sorting modes // default for all categories except DMs (behaves like manual) SidebarCategorySortDefault SidebarCategorySorting = "" @@ -38,13 +36,6 @@ const ( SidebarCategorySortAlphabetical SidebarCategorySorting = "alpha" ) -var SystemSidebarCategories = []SidebarCategoryType{ - SidebarCategoryChannels, - SidebarCategoryDirectMessages, - SidebarCategoryFavorites, - SidebarCategoryApps, -} - // SidebarCategory represents the corresponding DB table type SidebarCategory struct { Id string `json:"id"` @@ -86,7 +77,7 @@ type SidebarChannel struct { type SidebarChannels []*SidebarChannel type SidebarCategoriesWithChannels []*SidebarCategoryWithChannels -var categoryIdPattern = regexp.MustCompile("(favorites|channels|direct_messages|apps)_[a-z0-9]{26}_[a-z0-9]{26}") +var categoryIdPattern = regexp.MustCompile("(favorites|channels|direct_messages)_[a-z0-9]{26}_[a-z0-9]{26}") func IsValidCategoryId(s string) bool { // Category IDs can either be regular IDs diff --git a/server/public/model/feature_flags.go b/server/public/model/feature_flags.go index 9c28f9795b..c58d454d34 100644 --- a/server/public/model/feature_flags.go +++ b/server/public/model/feature_flags.go @@ -75,8 +75,6 @@ type FeatureFlags struct { DeprecateCloudFree bool - AppsSidebarCategory bool - CloudReverseTrial bool } @@ -106,7 +104,6 @@ func (f *FeatureFlags) SetDefaults() { f.WysiwygEditor = false f.OnboardingAutoShowLinkedBoard = false f.OnboardingTourTips = true - f.AppsSidebarCategory = false f.CloudReverseTrial = false } diff --git a/webapp/channels/src/packages/mattermost-redux/src/selectors/entities/preferences.test.ts b/webapp/channels/src/packages/mattermost-redux/src/selectors/entities/preferences.test.ts index cf5e7e4665..cb7eca1570 100644 --- a/webapp/channels/src/packages/mattermost-redux/src/selectors/entities/preferences.test.ts +++ b/webapp/channels/src/packages/mattermost-redux/src/selectors/entities/preferences.test.ts @@ -732,41 +732,3 @@ describe('shouldShowUnreadsCategory', () => { expect(Selectors.shouldShowUnreadsCategory(state)).toBe(true); }); }); - -describe('get feature flags', () => { - test('should check the value of feature flag AppsSidebarCategory', () => { - let state = { - entities: { - general: { - config: {}, - }, - }, - } as GlobalState; - - expect(Selectors.appsSidebarCategoryEnabled(state)).toBe(false); - - state = { - entities: { - general: { - config: { - FeatureFlagAppsSidebarCategory: 'false', - }, - }, - }, - } as GlobalState; - - expect(Selectors.appsSidebarCategoryEnabled(state)).toBe(false); - - state = { - entities: { - general: { - config: { - FeatureFlagAppsSidebarCategory: 'true', - }, - }, - }, - } as GlobalState; - - expect(Selectors.appsSidebarCategoryEnabled(state)).toBe(true); - }); -}); diff --git a/webapp/channels/src/packages/mattermost-redux/src/selectors/entities/preferences.ts b/webapp/channels/src/packages/mattermost-redux/src/selectors/entities/preferences.ts index 2fa981c5db..55152b0ce7 100644 --- a/webapp/channels/src/packages/mattermost-redux/src/selectors/entities/preferences.ts +++ b/webapp/channels/src/packages/mattermost-redux/src/selectors/entities/preferences.ts @@ -306,7 +306,3 @@ export function deprecateCloudFree(state: GlobalState): boolean { export function cloudReverseTrial(state: GlobalState): boolean { return getFeatureFlagValue(state, 'CloudReverseTrial') === 'true'; } - -export function appsSidebarCategoryEnabled(state: GlobalState): boolean { - return getFeatureFlagValue(state, 'AppsSidebarCategory') === 'true'; -} diff --git a/webapp/platform/types/src/config.ts b/webapp/platform/types/src/config.ts index fde915055b..1b8d8749ca 100644 --- a/webapp/platform/types/src/config.ts +++ b/webapp/platform/types/src/config.ts @@ -119,7 +119,6 @@ export type ClientConfig = { ExperimentalViewArchivedChannels: string; FileLevel: string; FeatureFlagAppsEnabled: string; - FeatureFlagAppsSidebarCategory: string; FeatureFlagBoardsProduct: string; FeatureFlagCallsEnabled: string; FeatureFlagGraphQL: string;