diff --git a/store/sqlstore/channel_store.go b/store/sqlstore/channel_store.go index a46e3677d8..e7f3611a11 100644 --- a/store/sqlstore/channel_store.go +++ b/store/sqlstore/channel_store.go @@ -3581,19 +3581,56 @@ func (s SqlChannelStore) CreateSidebarCategory(userId, teamId string, newCategor if err = transaction.Insert(category); err != nil { return nil, model.NewAppError("SqlPostStore.CreateSidebarCategory", "store.sql_channel.sidebar_categories.app_error", nil, err.Error(), http.StatusInternalServerError) } - var channels []interface{} - runningOrder := 0 - for _, channelID := range newCategory.Channels { - channels = append(channels, &model.SidebarChannel{ - ChannelId: channelID, - CategoryId: newCategoryId, - SortOrder: int64(runningOrder), - UserId: userId, - }) - runningOrder += model.MinimalSidebarSortDistance - } - if err = transaction.Insert(channels...); err != nil { - return nil, model.NewAppError("SqlPostStore.CreateSidebarCategory", "store.sql_channel.sidebar_categories.app_error", nil, err.Error(), http.StatusInternalServerError) + + if len(newCategory.Channels) > 0 { + channelIdsKeys, deleteParams := MapStringsToQueryParams(newCategory.Channels, "ChannelId") + deleteParams["UserId"] = userId + deleteParams["TeamId"] = teamId + + // Remove any channels from their previous categories and add them to the new one + var deleteQuery string + if s.DriverName() == model.DATABASE_DRIVER_MYSQL { + deleteQuery = ` + DELETE + SidebarChannels + FROM + SidebarChannels + JOIN + SidebarCategories ON SidebarChannels.CategoryId = SidebarCategories.Id + WHERE + SidebarChannels.UserId = :UserId + AND SidebarChannels.ChannelId IN ` + channelIdsKeys + ` + AND SidebarCategories.TeamId = :TeamId` + } else { + deleteQuery = ` + DELETE FROM + SidebarChannels + USING + SidebarCategories + WHERE + SidebarChannels.CategoryId = SidebarCategories.Id + AND SidebarChannels.UserId = :UserId + AND SidebarChannels.ChannelId IN ` + channelIdsKeys + ` + AND SidebarCategories.TeamId = :TeamId` + } + + _, err = transaction.Exec(deleteQuery, deleteParams) + if err != nil { + return nil, model.NewAppError("SqlPostStore.CreateSidebarCategory", "store.sql_channel.sidebar_categories.app_error", nil, err.Error(), http.StatusInternalServerError) + } + + var channels []interface{} + for i, channelID := range newCategory.Channels { + channels = append(channels, &model.SidebarChannel{ + ChannelId: channelID, + CategoryId: newCategoryId, + SortOrder: int64(i * model.MinimalSidebarSortDistance), + UserId: userId, + }) + } + if err = transaction.Insert(channels...); err != nil { + return nil, model.NewAppError("SqlPostStore.CreateSidebarCategory", "store.sql_channel.sidebar_categories.app_error", nil, err.Error(), http.StatusInternalServerError) + } } // now we re-order the categories according to the new order diff --git a/store/storetest/channel_store.go b/store/storetest/channel_store.go index 3d67b3d858..4114b29c22 100644 --- a/store/storetest/channel_store.go +++ b/store/storetest/channel_store.go @@ -102,6 +102,7 @@ func TestChannelStore(t *testing.T, ss store.Store, s SqlSupplier) { t.Run("GetChannelsBatchForIndexing", func(t *testing.T) { testChannelStoreGetChannelsBatchForIndexing(t, ss) }) t.Run("GroupSyncedChannelCount", func(t *testing.T) { testGroupSyncedChannelCount(t, ss) }) t.Run("CreateInitialSidebarCategories", func(t *testing.T) { testCreateInitialSidebarCategories(t, ss) }) + t.Run("CreateSidebarCategory", func(t *testing.T) { testCreateSidebarCategory(t, ss) }) t.Run("GetSidebarCategory", func(t *testing.T) { testGetSidebarCategory(t, ss, s) }) t.Run("GetSidebarCategories", func(t *testing.T) { testGetSidebarCategories(t, ss) }) t.Run("UpdateSidebarCategories", func(t *testing.T) { testUpdateSidebarCategories(t, ss, s) }) @@ -8132,6 +8133,164 @@ func testCreateInitialSidebarCategories(t *testing.T, ss store.Store) { }) } +func testCreateSidebarCategory(t *testing.T, ss store.Store) { + t.Run("should place the new category second if Favorites comes first", func(t *testing.T) { + userId := model.NewId() + teamId := model.NewId() + + nErr := ss.Channel().CreateInitialSidebarCategories(userId, teamId) + require.Nil(t, nErr) + + // Create the category + created, err := ss.Channel().CreateSidebarCategory(userId, teamId, &model.SidebarCategoryWithChannels{ + SidebarCategory: model.SidebarCategory{ + DisplayName: model.NewId(), + }, + }) + require.Nil(t, err) + + // Confirm that it comes second + res, err := ss.Channel().GetSidebarCategories(userId, teamId) + require.Nil(t, err) + require.Len(t, res.Categories, 4) + 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() + teamId := model.NewId() + + nErr := ss.Channel().CreateInitialSidebarCategories(userId, teamId) + require.Nil(t, nErr) + + // Re-arrange the categories so that Favorites comes last + categories, err := ss.Channel().GetSidebarCategories(userId, teamId) + require.Nil(t, err) + require.Len(t, categories.Categories, 3) + require.Equal(t, model.SidebarCategoryFavorites, categories.Categories[0].Type) + + err = ss.Channel().UpdateSidebarCategoryOrder(userId, teamId, []string{ + categories.Categories[1].Id, + categories.Categories[2].Id, + categories.Categories[0].Id, + }) + require.Nil(t, err) + + // Create the category + created, err := ss.Channel().CreateSidebarCategory(userId, teamId, &model.SidebarCategoryWithChannels{ + SidebarCategory: model.SidebarCategory{ + DisplayName: model.NewId(), + }, + }) + require.Nil(t, err) + + // Confirm that it comes first + res, err := ss.Channel().GetSidebarCategories(userId, teamId) + require.Nil(t, err) + require.Len(t, res.Categories, 4) + 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() + teamId := model.NewId() + + nErr := ss.Channel().CreateInitialSidebarCategories(userId, teamId) + require.Nil(t, nErr) + + // Create some channels + channel1, err := ss.Channel().Save(&model.Channel{ + Type: model.CHANNEL_OPEN, + TeamId: teamId, + Name: model.NewId(), + }, 100) + require.Nil(t, err) + channel2, err := ss.Channel().Save(&model.Channel{ + Type: model.CHANNEL_OPEN, + TeamId: teamId, + Name: model.NewId(), + }, 100) + require.Nil(t, err) + + // Create the category + created, err := ss.Channel().CreateSidebarCategory(userId, teamId, &model.SidebarCategoryWithChannels{ + SidebarCategory: model.SidebarCategory{ + DisplayName: model.NewId(), + }, + Channels: []string{channel2.Id, channel1.Id}, + }) + require.Nil(t, err) + assert.Equal(t, []string{channel2.Id, channel1.Id}, created.Channels) + + // Get the channel again to ensure that the SidebarChannels were saved correctly + res, err := ss.Channel().GetSidebarCategory(created.Id) + require.Nil(t, err) + assert.Equal(t, []string{channel2.Id, channel1.Id}, res.Channels) + }) + + t.Run("should remove any channels from their previous categories", func(t *testing.T) { + userId := model.NewId() + teamId := model.NewId() + + nErr := ss.Channel().CreateInitialSidebarCategories(userId, teamId) + require.Nil(t, nErr) + + categories, err := ss.Channel().GetSidebarCategories(userId, teamId) + require.Nil(t, err) + require.Len(t, categories.Categories, 3) + + 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.CHANNEL_OPEN, + TeamId: teamId, + Name: model.NewId(), + }, 100) + require.Nil(t, nErr) + channel2, nErr := ss.Channel().Save(&model.Channel{ + Type: model.CHANNEL_OPEN, + TeamId: teamId, + Name: model.NewId(), + }, 100) + require.Nil(t, nErr) + + // Assign them to categories + favoritesCategory.Channels = []string{channel1.Id} + channelsCategory.Channels = []string{channel2.Id} + _, err = ss.Channel().UpdateSidebarCategories(userId, teamId, []*model.SidebarCategoryWithChannels{ + favoritesCategory, + channelsCategory, + }) + require.Nil(t, err) + + // Create the category + created, err := ss.Channel().CreateSidebarCategory(userId, teamId, &model.SidebarCategoryWithChannels{ + SidebarCategory: model.SidebarCategory{ + DisplayName: model.NewId(), + }, + Channels: []string{channel2.Id, channel1.Id}, + }) + require.Nil(t, err) + assert.Equal(t, []string{channel2.Id, channel1.Id}, created.Channels) + + // Confirm that the channels were removed from their original categories + res, err := ss.Channel().GetSidebarCategory(favoritesCategory.Id) + require.Nil(t, err) + assert.Equal(t, []string{}, res.Channels) + + res, err = ss.Channel().GetSidebarCategory(channelsCategory.Id) + require.Nil(t, err) + assert.Equal(t, []string{}, res.Channels) + }) +} + func testDeleteSidebarCategory(t *testing.T, ss store.Store, s SqlSupplier) { setupInitialSidebarCategories := func(t *testing.T, ss store.Store) (string, string) { userId := model.NewId()