// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. package api4 import ( "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/mattermost/mattermost-server/v6/model" "github.com/mattermost/mattermost-server/v6/store" "github.com/mattermost/mattermost-server/v6/utils/testutils" ) // Top Reactions func TestGetTopReactionsForTeamSince(t *testing.T) { th := Setup(t).InitBasic() defer th.TearDown() th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuProfessional)) client := th.Client userId := th.BasicUser.Id user2Id := th.BasicUser2.Id post1 := &model.Post{UserId: userId, ChannelId: th.BasicChannel.Id, Message: "zz" + model.NewId() + "a"} post2 := &model.Post{UserId: userId, ChannelId: th.BasicChannel.Id, Message: "zz" + model.NewId() + "a"} post3 := &model.Post{UserId: userId, ChannelId: th.BasicChannel.Id, Message: "zz" + model.NewId() + "a"} post4 := &model.Post{UserId: user2Id, ChannelId: th.BasicChannel.Id, Message: "zz" + model.NewId() + "a"} post5 := &model.Post{UserId: user2Id, ChannelId: th.BasicChannel.Id, Message: "zz" + model.NewId() + "a"} post1, _, _ = client.CreatePost(post1) post2, _, _ = client.CreatePost(post2) post3, _, _ = client.CreatePost(post3) post4, _, _ = client.CreatePost(post4) post5, _, _ = client.CreatePost(post5) userReactions := []*model.Reaction{ { UserId: userId, PostId: post1.Id, EmojiName: "happy", }, { UserId: user2Id, PostId: post1.Id, EmojiName: "happy", }, { UserId: userId, PostId: post1.Id, EmojiName: "sad", }, { UserId: user2Id, PostId: post1.Id, EmojiName: "sad", }, { UserId: userId, PostId: post1.Id, EmojiName: "smile", }, { UserId: userId, PostId: post1.Id, EmojiName: "joy", }, { UserId: userId, PostId: post1.Id, EmojiName: "100", }, { UserId: userId, PostId: post2.Id, EmojiName: "sad", }, { UserId: userId, PostId: post2.Id, EmojiName: "smile", }, { UserId: userId, PostId: post2.Id, EmojiName: "joy", }, { UserId: userId, PostId: post2.Id, EmojiName: "100", }, { UserId: userId, PostId: post3.Id, EmojiName: "smile", }, { UserId: user2Id, PostId: post3.Id, EmojiName: "smile", }, { UserId: userId, PostId: post3.Id, EmojiName: "joy", }, { UserId: userId, PostId: post3.Id, EmojiName: "100", }, { UserId: userId, PostId: post4.Id, EmojiName: "joy", }, { UserId: user2Id, PostId: post4.Id, EmojiName: "joy", }, { UserId: userId, PostId: post4.Id, EmojiName: "100", }, { UserId: userId, PostId: post5.Id, EmojiName: "100", }, { UserId: user2Id, PostId: post5.Id, EmojiName: "100", }, { UserId: user2Id, PostId: post5.Id, EmojiName: "+1", }, { UserId: userId, PostId: post1.Id, EmojiName: "100", CreateAt: model.GetMillisForTime(time.Now().Add(time.Hour * time.Duration(-25))), }, } for _, userReaction := range userReactions { _, err := th.App.Srv().Store().Reaction().Save(userReaction) require.NoError(t, err) } teamId := th.BasicChannel.TeamId var expectedTopReactions [5]*model.TopReaction expectedTopReactions[0] = &model.TopReaction{EmojiName: "100", Count: int64(6)} expectedTopReactions[1] = &model.TopReaction{EmojiName: "joy", Count: int64(5)} expectedTopReactions[2] = &model.TopReaction{EmojiName: "smile", Count: int64(4)} expectedTopReactions[3] = &model.TopReaction{EmojiName: "sad", Count: int64(3)} expectedTopReactions[4] = &model.TopReaction{EmojiName: "happy", Count: int64(2)} t.Run("get-top-reactions-for-team-since", func(t *testing.T) { topReactions, _, err := client.GetTopReactionsForTeamSince(teamId, model.TimeRangeToday, 0, 5) require.NoError(t, err) reactions := topReactions.Items for i, reaction := range reactions { assert.Equal(t, expectedTopReactions[i].EmojiName, reaction.EmojiName) assert.Equal(t, expectedTopReactions[i].Count, reaction.Count) } topReactions, _, err = client.GetTopReactionsForTeamSince(teamId, model.TimeRangeToday, 1, 5) require.NoError(t, err) reactions = topReactions.Items assert.Equal(t, "+1", reactions[0].EmojiName) assert.Equal(t, int64(1), reactions[0].Count) }) t.Run("get-top-reactions-for-team-since exclude channels user is not member of", func(t *testing.T) { excludedChannel := th.CreatePrivateChannel() for i := 0; i < 10; i++ { post, _, err := client.CreatePost(&model.Post{UserId: userId, ChannelId: excludedChannel.Id, Message: "zz" + model.NewId() + "a"}) require.NoError(t, err) reaction := &model.Reaction{ UserId: userId, PostId: post.Id, EmojiName: "confused", } _, err = th.App.Srv().Store().Reaction().Save(reaction) require.NoError(t, err) } th.RemoveUserFromChannel(th.BasicUser, excludedChannel) topReactions, _, err := client.GetTopReactionsForTeamSince(teamId, model.TimeRangeToday, 0, 5) require.NoError(t, err) reactions := topReactions.Items for i, reaction := range reactions { assert.Equal(t, expectedTopReactions[i].EmojiName, reaction.EmojiName) assert.Equal(t, expectedTopReactions[i].Count, reaction.Count) } topReactions, _, err = client.GetTopReactionsForTeamSince(teamId, model.TimeRangeToday, 1, 5) require.NoError(t, err) reactions = topReactions.Items assert.Equal(t, "+1", reactions[0].EmojiName) assert.Equal(t, int64(1), reactions[0].Count) }) t.Run("get-top-reactions-for-team-since invalid team id", func(t *testing.T) { _, resp, err := client.GetTopReactionsForTeamSince("12345", model.TimeRangeToday, 0, 5) assert.Error(t, err) CheckBadRequestStatus(t, resp) _, resp, err = client.GetTopReactionsForTeamSince(model.NewId(), model.TimeRangeToday, 0, 5) assert.Error(t, err) CheckNotFoundStatus(t, resp) }) t.Run("get-top-reactions-for-team-since invalid time range", func(t *testing.T) { _, resp, err := client.GetTopReactionsForTeamSince(teamId, "7_days", 0, 5) require.Error(t, err) CheckBadRequestStatus(t, resp) }) t.Run("get-top-reactions-for-team-since not a member of team", func(t *testing.T) { th.UnlinkUserFromTeam(th.BasicUser, th.BasicTeam) _, resp, err := client.GetTopReactionsForTeamSince(teamId, model.TimeRangeToday, 0, 5) assert.Error(t, err) CheckForbiddenStatus(t, resp) }) t.Run("get-top-reactions-for-team-since invalid license", func(t *testing.T) { th.App.Srv().SetLicense(model.NewTestLicense("")) _, resp, err := client.GetTopReactionsForTeamSince(teamId, model.TimeRangeToday, 0, 5) assert.Error(t, err) CheckNotImplementedStatus(t, resp) }) } func TestGetTopReactionsForUserSince(t *testing.T) { th := Setup(t).InitBasic() defer th.TearDown() client := th.Client userId := th.BasicUser.Id post1 := &model.Post{UserId: userId, ChannelId: th.BasicChannel.Id, Message: "zz" + model.NewId() + "a"} post2 := &model.Post{UserId: userId, ChannelId: th.BasicChannel.Id, Message: "zz" + model.NewId() + "a"} post3 := &model.Post{UserId: userId, ChannelId: th.BasicChannel.Id, Message: "zz" + model.NewId() + "a"} post4 := &model.Post{UserId: userId, ChannelId: th.BasicChannel.Id, Message: "zz" + model.NewId() + "a"} post5 := &model.Post{UserId: userId, ChannelId: th.BasicChannel.Id, Message: "zz" + model.NewId() + "a"} post6 := &model.Post{UserId: userId, ChannelId: th.BasicChannel.Id, Message: "zz" + model.NewId() + "a"} post1, _, _ = client.CreatePost(post1) post2, _, _ = client.CreatePost(post2) post3, _, _ = client.CreatePost(post3) post4, _, _ = client.CreatePost(post4) post5, _, _ = client.CreatePost(post5) post6, _, _ = client.CreatePost(post6) userReactions := []*model.Reaction{ { UserId: userId, PostId: post1.Id, EmojiName: "happy", }, { UserId: userId, PostId: post2.Id, EmojiName: "happy", }, { UserId: userId, PostId: post3.Id, EmojiName: "happy", }, { UserId: userId, PostId: post4.Id, EmojiName: "happy", }, { UserId: userId, PostId: post5.Id, EmojiName: "happy", }, { UserId: userId, PostId: post6.Id, EmojiName: "happy", }, { UserId: userId, PostId: post1.Id, EmojiName: "smile", }, { UserId: userId, PostId: post2.Id, EmojiName: "smile", }, { UserId: userId, PostId: post3.Id, EmojiName: "smile", }, { UserId: userId, PostId: post4.Id, EmojiName: "smile", }, { UserId: userId, PostId: post5.Id, EmojiName: "smile", }, { UserId: userId, PostId: post1.Id, EmojiName: "+1", }, { UserId: userId, PostId: post2.Id, EmojiName: "+1", }, { UserId: userId, PostId: post3.Id, EmojiName: "+1", }, { UserId: userId, PostId: post4.Id, EmojiName: "+1", }, { UserId: userId, PostId: post1.Id, EmojiName: "heart", }, { UserId: userId, PostId: post2.Id, EmojiName: "heart", }, { UserId: userId, PostId: post3.Id, EmojiName: "heart", }, { UserId: userId, PostId: post1.Id, EmojiName: "blush", }, { UserId: userId, PostId: post2.Id, EmojiName: "blush", }, { UserId: userId, PostId: post1.Id, EmojiName: "100", }, { UserId: userId, PostId: post1.Id, EmojiName: "100", CreateAt: model.GetMillisForTime(time.Now().Add(time.Hour * time.Duration(-25))), }, } for _, userReaction := range userReactions { _, err := th.App.Srv().Store().Reaction().Save(userReaction) require.NoError(t, err) } teamId := th.BasicChannel.TeamId var expectedTopReactions [5]*model.TopReaction expectedTopReactions[0] = &model.TopReaction{EmojiName: "happy", Count: int64(6)} expectedTopReactions[1] = &model.TopReaction{EmojiName: "smile", Count: int64(5)} expectedTopReactions[2] = &model.TopReaction{EmojiName: "+1", Count: int64(4)} expectedTopReactions[3] = &model.TopReaction{EmojiName: "heart", Count: int64(3)} expectedTopReactions[4] = &model.TopReaction{EmojiName: "blush", Count: int64(2)} t.Run("get-top-reactions-for-user-since", func(t *testing.T) { topReactions, _, err := client.GetTopReactionsForUserSince(teamId, model.TimeRangeToday, 0, 5) require.NoError(t, err) reactions := topReactions.Items for i, reaction := range reactions { assert.Equal(t, expectedTopReactions[i].EmojiName, reaction.EmojiName) assert.Equal(t, expectedTopReactions[i].Count, reaction.Count) } topReactions, _, err = client.GetTopReactionsForUserSince(teamId, model.TimeRangeToday, 1, 5) require.NoError(t, err) reactions = topReactions.Items assert.Equal(t, "100", reactions[0].EmojiName) assert.Equal(t, int64(1), reactions[0].Count) }) t.Run("get-top-reactions-for-user-since invalid team id", func(t *testing.T) { _, resp, err := client.GetTopReactionsForUserSince("invalid_team_id", model.TimeRangeToday, 0, 5) assert.Error(t, err) CheckBadRequestStatus(t, resp) _, resp, err = client.GetTopReactionsForUserSince(model.NewId(), model.TimeRangeToday, 0, 5) assert.Error(t, err) CheckNotFoundStatus(t, resp) }) t.Run("get-top-reactions-for-user-since invalid time range", func(t *testing.T) { _, resp, err := client.GetTopReactionsForUserSince(teamId, "7_days", 0, 5) require.Error(t, err) CheckBadRequestStatus(t, resp) }) t.Run("get-top-reactions-for-user-since not a member of team", func(t *testing.T) { th.UnlinkUserFromTeam(th.BasicUser, th.BasicTeam) _, resp, err := client.GetTopReactionsForUserSince(teamId, model.TimeRangeToday, 0, 5) assert.Error(t, err) CheckForbiddenStatus(t, resp) }) } // Top Channels func TestGetTopChannelsForTeamSince(t *testing.T) { th := Setup(t).InitBasic() defer th.TearDown() th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuProfessional)) client := th.Client userId := th.BasicUser.Id channel4 := th.CreatePublicChannel() channel5 := th.CreatePrivateChannel() channel6 := th.CreatePrivateChannel() th.App.AddUserToChannel(th.Context, th.BasicUser, channel4, false) th.App.AddUserToChannel(th.Context, th.BasicUser, channel5, false) th.App.AddUserToChannel(th.Context, th.BasicUser, channel6, false) channelIDs := [6]string{th.BasicChannel.Id, th.BasicChannel2.Id, th.BasicPrivateChannel.Id, channel4.Id, channel5.Id, channel6.Id} i := len(channelIDs) for _, channelID := range channelIDs { for j := i; j > 0; j-- { _, _, err := client.CreatePost(&model.Post{UserId: userId, ChannelId: channelID, Message: "zz" + model.NewId() + "a"}) require.NoError(t, err) } i-- } teamId := th.BasicChannel.TeamId expectedTopChannels := []struct { ID string MessageCount int64 }{ {ID: th.BasicChannel.Id, MessageCount: 7}, {ID: th.BasicChannel2.Id, MessageCount: 5}, {ID: th.BasicPrivateChannel.Id, MessageCount: 4}, {ID: channel4.Id, MessageCount: 3}, {ID: channel5.Id, MessageCount: 2}, } t.Run("get-top-channels-for-team-since", func(t *testing.T) { topChannels, _, err := client.GetTopChannelsForTeamSince(teamId, model.TimeRangeToday, 0, 5) require.NoError(t, err) for i, channel := range topChannels.Items { assert.Equal(t, expectedTopChannels[i].ID, channel.ID) assert.Equal(t, expectedTopChannels[i].MessageCount, channel.MessageCount) } topChannels, _, err = client.GetTopChannelsForTeamSince(teamId, model.TimeRangeToday, 1, 5) require.NoError(t, err) assert.Equal(t, channel6.Id, topChannels.Items[0].ID) assert.Equal(t, int64(1), topChannels.Items[0].MessageCount) t.Run("has post count by day", func(t *testing.T) { require.NotNil(t, topChannels.PostCountByDuration) }) }) t.Run("get-top-channels-for-user-since exclude channels user is not member of", func(t *testing.T) { excludedChannel := th.CreatePrivateChannel() for i := 0; i < 10; i++ { _, _, err := client.CreatePost(&model.Post{UserId: userId, ChannelId: excludedChannel.Id, Message: "zz" + model.NewId() + "a"}) require.NoError(t, err) } th.RemoveUserFromChannel(th.BasicUser, excludedChannel) topChannels, _, err := client.GetTopChannelsForTeamSince(teamId, model.TimeRangeToday, 0, 5) require.NoError(t, err) for i, channel := range topChannels.Items { assert.Equal(t, expectedTopChannels[i].ID, channel.ID) assert.Equal(t, expectedTopChannels[i].MessageCount, channel.MessageCount) } }) t.Run("get-top-channels-for-team-since invalid team id", func(t *testing.T) { _, resp, err := client.GetTopChannelsForTeamSince("12345", model.TimeRangeToday, 0, 5) assert.Error(t, err) CheckBadRequestStatus(t, resp) _, resp, err = client.GetTopChannelsForTeamSince(model.NewId(), model.TimeRangeToday, 0, 5) assert.Error(t, err) CheckNotFoundStatus(t, resp) }) t.Run("get-top-channels-for-team-since invalid time range", func(t *testing.T) { _, resp, err := client.GetTopChannelsForTeamSince(teamId, "7_days", 0, 5) assert.Error(t, err) CheckBadRequestStatus(t, resp) }) t.Run("get-top-channels-for-team-since not a member of team", func(t *testing.T) { th.UnlinkUserFromTeam(th.BasicUser, th.BasicTeam) _, resp, err := client.GetTopChannelsForTeamSince(teamId, model.TimeRangeToday, 0, 5) assert.Error(t, err) CheckForbiddenStatus(t, resp) }) t.Run("get-top-channels-for-team-since invalid license", func(t *testing.T) { th.App.Srv().SetLicense(model.NewTestLicense("")) _, resp, err := client.GetTopChannelsForTeamSince(teamId, model.TimeRangeToday, 0, 5) assert.Error(t, err) CheckNotImplementedStatus(t, resp) }) } func TestGetTopChannelsForUserSince(t *testing.T) { th := Setup(t).InitBasic() defer th.TearDown() client := th.Client userId := th.BasicUser.Id channel4 := th.CreatePublicChannel() channel5 := th.CreatePrivateChannel() channel6 := th.CreatePrivateChannel() th.App.AddUserToChannel(th.Context, th.BasicUser, channel4, false) th.App.AddUserToChannel(th.Context, th.BasicUser, channel5, false) th.App.AddUserToChannel(th.Context, th.BasicUser, channel6, false) channelIDs := [6]string{th.BasicChannel.Id, th.BasicChannel2.Id, th.BasicPrivateChannel.Id, channel4.Id, channel5.Id, channel6.Id} i := len(channelIDs) for _, channelID := range channelIDs { for j := i; j > 0; j-- { _, _, err := client.CreatePost(&model.Post{UserId: userId, ChannelId: channelID, Message: "zz" + model.NewId() + "a"}) require.NoError(t, err) } i-- } teamId := th.BasicChannel.TeamId expectedTopChannels := []struct { ID string MessageCount int64 }{ {ID: th.BasicChannel.Id, MessageCount: 6}, {ID: th.BasicChannel2.Id, MessageCount: 5}, {ID: th.BasicPrivateChannel.Id, MessageCount: 4}, {ID: channel4.Id, MessageCount: 3}, {ID: channel5.Id, MessageCount: 2}, } t.Run("get-top-channels-for-user-since", func(t *testing.T) { topChannels, _, err := client.GetTopChannelsForUserSince(teamId, model.TimeRangeToday, 0, 5) require.NoError(t, err) for i, channel := range topChannels.Items { assert.Equal(t, expectedTopChannels[i].ID, channel.ID) assert.Equal(t, expectedTopChannels[i].MessageCount, channel.MessageCount) } topChannels, _, err = client.GetTopChannelsForUserSince("", model.TimeRangeToday, 1, 5) require.NoError(t, err) assert.Equal(t, channel6.Id, topChannels.Items[0].ID) assert.Equal(t, int64(1), topChannels.Items[0].MessageCount) t.Run("has post count by day", func(t *testing.T) { require.NotNil(t, topChannels.PostCountByDuration) }) }) t.Run("get-top-channels-for-user-since invalid team id", func(t *testing.T) { _, resp, err := client.GetTopChannelsForUserSince("12345", model.TimeRangeToday, 0, 5) assert.Error(t, err) CheckBadRequestStatus(t, resp) _, resp, err = client.GetTopChannelsForUserSince(model.NewId(), model.TimeRangeToday, 0, 5) assert.Error(t, err) CheckNotFoundStatus(t, resp) }) t.Run("get-top-channels-for-user-since invalid time range", func(t *testing.T) { _, resp, err := client.GetTopChannelsForUserSince(teamId, "7_days", 0, 5) assert.Error(t, err) CheckBadRequestStatus(t, resp) }) t.Run("get-top-channels-for-user-since not a member of team", func(t *testing.T) { th.UnlinkUserFromTeam(th.BasicUser, th.BasicTeam) _, resp, err := client.GetTopChannelsForUserSince(teamId, model.TimeRangeToday, 0, 5) assert.Error(t, err) CheckForbiddenStatus(t, resp) }) } func TestGetTopThreadsForTeamSince(t *testing.T) { th := Setup(t).InitBasic() defer th.TearDown() th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuProfessional)) th.LoginBasic() client := th.Client // create a public channel, a private channel channelPublic := th.BasicChannel channelPrivate := th.BasicPrivateChannel th.App.AddUserToChannel(th.Context, th.BasicUser, channelPublic, false) th.App.AddUserToChannel(th.Context, th.BasicUser, channelPrivate, false) th.App.AddUserToChannel(th.Context, th.BasicUser2, channelPublic, false) th.App.RemoveUserFromChannel(th.Context, th.BasicUser2.Id, th.BasicUser.Id, channelPrivate) // create two threads: one in public channel, one in private // post in public channel has both users interacting, post in private only has user1 interacting rootPostPublicChannel, appErr := th.App.CreatePost(th.Context, &model.Post{ UserId: th.BasicUser.Id, ChannelId: channelPublic.Id, Message: "root post pub", }, channelPublic, false, true) require.Nil(t, appErr) _, appErr = th.App.CreatePost(th.Context, &model.Post{ UserId: th.BasicUser2.Id, ChannelId: channelPublic.Id, RootId: rootPostPublicChannel.Id, Message: "reply post 1", }, channelPublic, false, true) require.Nil(t, appErr) rootPostPrivateChannel, appErr := th.App.CreatePost(th.Context, &model.Post{ UserId: th.BasicUser.Id, ChannelId: channelPrivate.Id, Message: "root post priv", }, channelPrivate, false, true) require.Nil(t, appErr) _, appErr = th.App.CreatePost(th.Context, &model.Post{ UserId: th.BasicUser.Id, ChannelId: channelPrivate.Id, RootId: rootPostPrivateChannel.Id, Message: "reply post 1", }, channelPrivate, false, true) require.Nil(t, appErr) _, appErr = th.App.CreatePost(th.Context, &model.Post{ UserId: th.BasicUser.Id, ChannelId: channelPrivate.Id, RootId: rootPostPrivateChannel.Id, Message: "reply post 2", }, channelPrivate, false, true) require.Nil(t, appErr) // get top threads for team, as user 1 and user 2 // user 1, 2 should see both threads topTeamThreadsByUser1, _, _ := client.GetTopThreadsForTeamSince(th.BasicTeam.Id, model.TimeRangeToday, 0, 10) require.Nil(t, appErr) require.Len(t, topTeamThreadsByUser1.Items, 2) require.Equal(t, topTeamThreadsByUser1.Items[0].Post.Id, rootPostPrivateChannel.Id) require.Equal(t, topTeamThreadsByUser1.Items[1].Post.Id, rootPostPublicChannel.Id) client.Logout() th.LoginBasic2() client = th.Client topTeamThreadsByUser2, _, _ := client.GetTopThreadsForTeamSince(th.BasicTeam.Id, model.TimeRangeToday, 0, 10) require.Nil(t, appErr) require.Len(t, topTeamThreadsByUser2.Items, 1) require.Equal(t, topTeamThreadsByUser2.Items[0].Post.Id, rootPostPublicChannel.Id) // add user2 to private channel and it can see 2 top threads. th.AddUserToChannel(th.BasicUser2, channelPrivate) topTeamThreadsByUser2IncludingPrivate, _, _ := client.GetTopThreadsForTeamSince(th.BasicTeam.Id, model.TimeRangeToday, 0, 10) require.Nil(t, appErr) require.Len(t, topTeamThreadsByUser2IncludingPrivate.Items, 2) t.Run("get-top-threads-for-team-since invalid license", func(t *testing.T) { th.App.Srv().SetLicense(model.NewTestLicense("")) _, resp, err := client.GetTopThreadsForTeamSince(th.BasicTeam.Id, model.TimeRangeToday, 0, 5) assert.Error(t, err) CheckNotImplementedStatus(t, resp) }) } func TestGetTopThreadsForUserSince(t *testing.T) { th := Setup(t).InitBasic() defer th.TearDown() th.LoginBasic() client := th.Client // create a public channel, a private channel channelPublic := th.BasicChannel channelPrivate := th.BasicPrivateChannel th.App.AddUserToChannel(th.Context, th.BasicUser, channelPublic, false) th.App.AddUserToChannel(th.Context, th.BasicUser, channelPrivate, false) th.App.AddUserToChannel(th.Context, th.BasicUser2, channelPublic, false) // create two threads: one in public channel, one in private // post in public channel has both users interacting, post in private only has user1 interacting rootPostPublicChannel, appErr := th.App.CreatePost(th.Context, &model.Post{ UserId: th.BasicUser.Id, ChannelId: channelPublic.Id, Message: "root post pub", }, channelPublic, false, true) require.Nil(t, appErr) _, appErr = th.App.CreatePost(th.Context, &model.Post{ UserId: th.BasicUser2.Id, ChannelId: channelPublic.Id, RootId: rootPostPublicChannel.Id, Message: "reply post 1", }, channelPublic, false, true) require.Nil(t, appErr) rootPostPrivateChannel, appErr := th.App.CreatePost(th.Context, &model.Post{ UserId: th.BasicUser.Id, ChannelId: channelPrivate.Id, Message: "root post priv", }, channelPrivate, false, true) require.Nil(t, appErr) _, appErr = th.App.CreatePost(th.Context, &model.Post{ UserId: th.BasicUser.Id, ChannelId: channelPrivate.Id, RootId: rootPostPrivateChannel.Id, Message: "reply post 1", }, channelPrivate, false, true) require.Nil(t, appErr) _, appErr = th.App.CreatePost(th.Context, &model.Post{ UserId: th.BasicUser.Id, ChannelId: channelPrivate.Id, RootId: rootPostPrivateChannel.Id, Message: "reply post 2", }, channelPrivate, false, true) require.Nil(t, appErr) // get top threads for user, as user 1 and user 2 // user 1 should see both threads, while user 2 should see only thread in public channel // (even if user2 is in the private channel it hasn't interacted with the thread there.) topUser1Threads, _, _ := client.GetTopThreadsForUserSince(th.BasicTeam.Id, model.TimeRangeToday, 0, 10) require.Nil(t, appErr) require.Len(t, topUser1Threads.Items, 2) require.Equal(t, topUser1Threads.Items[0].Post.Id, rootPostPrivateChannel.Id) require.Equal(t, topUser1Threads.Items[0].Post.ReplyCount, int64(2)) require.Equal(t, topUser1Threads.Items[1].Post.Id, rootPostPublicChannel.Id) require.Contains(t, topUser1Threads.Items[1].Participants, th.BasicUser2.Id) require.Equal(t, topUser1Threads.Items[1].Post.ReplyCount, int64(1)) client.Logout() th.LoginBasic2() client = th.Client topUser2Threads, _, _ := client.GetTopThreadsForUserSince(th.BasicTeam.Id, model.TimeRangeToday, 0, 10) require.Nil(t, appErr) require.Len(t, topUser2Threads.Items, 1) require.Equal(t, topUser2Threads.Items[0].Post.Id, rootPostPublicChannel.Id) require.Equal(t, topUser2Threads.Items[0].Post.ReplyCount, int64(1)) // deleting the root post results in the thread not making it to top threads list _, appErr = th.App.DeletePost(th.Context, rootPostPublicChannel.Id, th.BasicUser.Id) require.Nil(t, appErr) client.Logout() th.LoginBasic() client = th.Client topUser1ThreadsAfterPost1Delete, _, _ := client.GetTopThreadsForUserSince(th.BasicTeam.Id, model.TimeRangeToday, 0, 10) require.Nil(t, appErr) require.Len(t, topUser1ThreadsAfterPost1Delete.Items, 1) client.Logout() th.LoginBasic2() client = th.Client // reply with user2 in thread2. deleting that reply, shouldn't give any top thread for user2 if the user2 unsubscribes to the thread after deleting the comment replyPostUser2InPrivate, appErr := th.App.CreatePost(th.Context, &model.Post{ UserId: th.BasicUser2.Id, ChannelId: channelPrivate.Id, RootId: rootPostPrivateChannel.Id, Message: "reply post 3", }, channelPrivate, false, true) require.Nil(t, appErr) topUser2ThreadsAfterPrivateReply, _, _ := client.GetTopThreadsForUserSince(th.BasicTeam.Id, model.TimeRangeToday, 0, 10) require.Nil(t, appErr) require.Len(t, topUser2ThreadsAfterPrivateReply.Items, 1) // deleting reply, and unfollowing thread _, appErr = th.App.DeletePost(th.Context, replyPostUser2InPrivate.Id, th.BasicUser2.Id) require.Nil(t, appErr) // unfollow thread _, err := th.App.Srv().Store().Thread().MaintainMembership(th.BasicUser2.Id, rootPostPrivateChannel.Id, store.ThreadMembershipOpts{ Following: false, UpdateFollowing: true, }) require.NoError(t, err) topUser2ThreadsAfterPrivateReplyDelete, _, _ := client.GetTopThreadsForUserSince(th.BasicTeam.Id, model.TimeRangeToday, 0, 10) require.Nil(t, appErr) require.Len(t, topUser2ThreadsAfterPrivateReplyDelete.Items, 0) } func TestGetTopInactiveChannelsForTeamSince(t *testing.T) { th := Setup(t).InitBasic() defer th.TearDown() // delete offtopic, town-square, th.basicchannel channel - which interferes with 'least' active channel results offTopicChannel, appErr := th.App.GetChannelByName(th.Context, "off-topic", th.BasicTeam.Id, false) require.Nil(t, appErr, "Expected nil, didn't receive nil") appErr = th.App.PermanentDeleteChannel(th.Context, offTopicChannel) require.Nil(t, appErr) townSquareChannel, appErr := th.App.GetChannelByName(th.Context, "town-square", th.BasicTeam.Id, false) require.Nil(t, appErr, "Expected nil, didn't receive nil") appErr = th.App.PermanentDeleteChannel(th.Context, townSquareChannel) require.Nil(t, appErr) basicChannel, appErr := th.App.GetChannel(th.Context, th.BasicChannel.Id) require.Nil(t, appErr, "Expected nil, didn't receive nil") appErr = th.App.PermanentDeleteChannel(th.Context, basicChannel) require.Nil(t, appErr) basicChannel2, appErr := th.App.GetChannel(th.Context, th.BasicChannel2.Id) require.Nil(t, appErr, "Expected nil, didn't receive nil") appErr = th.App.PermanentDeleteChannel(th.Context, basicChannel2) require.Nil(t, appErr) basicPrivateChannel, appErr := th.App.GetChannel(th.Context, th.BasicPrivateChannel.Id) require.Nil(t, appErr, "Expected nil, didn't receive nil") appErr = th.App.PermanentDeleteChannel(th.Context, basicPrivateChannel) require.Nil(t, appErr) th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuProfessional)) client := th.Client userId := th.BasicUser.Id channel4Req := &model.Channel{ DisplayName: "channel4", Name: GenerateTestChannelName(), Type: model.ChannelTypeOpen, TeamId: th.BasicTeam.Id, CreateAt: 1, } channel4, _, err := client.CreateChannel(channel4Req) require.NoError(t, err) channel5Req := &model.Channel{ DisplayName: "channel4", Name: GenerateTestChannelName(), Type: model.ChannelTypePrivate, TeamId: th.BasicTeam.Id, CreateAt: 1, } channel5, _, err := client.CreateChannel(channel5Req) require.NoError(t, err) channel6Req := &model.Channel{ DisplayName: "channel4", Name: GenerateTestChannelName(), Type: model.ChannelTypePrivate, TeamId: th.BasicTeam.Id, CreateAt: 1, } channel6, _, err := client.CreateChannel(channel6Req) require.NoError(t, err) th.App.AddUserToChannel(th.Context, th.BasicUser, channel4, false) th.App.AddUserToChannel(th.Context, th.BasicUser, channel5, false) th.App.AddUserToChannel(th.Context, th.BasicUser, channel6, false) channelIDs := [3]string{channel4.Id, channel5.Id, channel6.Id} i := len(channelIDs) for _, channelID := range channelIDs { for j := i; j > 0; j-- { _, _, err := client.CreatePost(&model.Post{UserId: userId, ChannelId: channelID, Message: "zz" + model.NewId() + "a"}) require.NoError(t, err) } i-- } teamId := th.BasicChannel.TeamId expectedTopChannels := []struct { ID string MessageCount int64 }{{ ID: channel6.Id, MessageCount: 1}, {ID: channel5.Id, MessageCount: 2}, {ID: channel4.Id, MessageCount: 3}, } t.Run("get-top-inactive-channels-for-team-since", func(t *testing.T) { topInactiveChannels, _, err := client.GetTopInactiveChannelsForTeamSince(teamId, model.TimeRangeToday, 0, 2) require.NoError(t, err) for i, channel := range topInactiveChannels.Items { assert.Equal(t, expectedTopChannels[i].ID, channel.ID) } topInactiveChannels, _, err = client.GetTopInactiveChannelsForTeamSince(teamId, model.TimeRangeToday, 1, 2) require.NoError(t, err) assert.Equal(t, channel4.Id, topInactiveChannels.Items[0].ID) }) t.Run("get-top-channels-for-user-since exclude channels user is not member of", func(t *testing.T) { excludedChannel := th.CreatePrivateChannel() for i := 0; i < 10; i++ { _, _, err := client.CreatePost(&model.Post{UserId: userId, ChannelId: excludedChannel.Id, Message: "zz" + model.NewId() + "a"}) require.NoError(t, err) } th.RemoveUserFromChannel(th.BasicUser, excludedChannel) topInactiveChannels, _, err := client.GetTopInactiveChannelsForUserSince(teamId, model.TimeRangeToday, 0, 3) require.NoError(t, err) for i, channel := range topInactiveChannels.Items { assert.Equal(t, expectedTopChannels[i].ID, channel.ID) } }) t.Run("get-top-inactive-channels-for-team-since invalid license", func(t *testing.T) { th.App.Srv().SetLicense(model.NewTestLicense("")) _, resp, err := client.GetTopInactiveChannelsForTeamSince(teamId, model.TimeRangeToday, 0, 5) assert.Error(t, err) CheckNotImplementedStatus(t, resp) }) } func TestGetTopDMsForUserSince(t *testing.T) { th := Setup(t).InitBasic() defer th.TearDown() th.ConfigStore.SetReadOnlyFF(false) defer th.ConfigStore.SetReadOnlyFF(true) th.App.UpdateConfig(func(c *model.Config) { *c.TeamSettings.EnableUserDeactivation = true }) th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableBotAccountCreation = true }) // basicuser1 - bu1, basicuser - bu // create dm channels for bu-bu, bu1-bu1, bu-bu1, bot-bu basicUser := th.BasicUser basicUser1 := th.BasicUser2 th.LoginBasic2() client := th.Client channelBu1Bu1, _, err := client.CreateDirectChannel(basicUser1.Id, basicUser1.Id) require.NoError(t, err) th.LoginBasic() client = th.Client channelBuBu, _, err := client.CreateDirectChannel(basicUser.Id, basicUser.Id) require.NoError(t, err) channelBuBu1, _, err := client.CreateDirectChannel(basicUser.Id, basicUser1.Id) require.NoError(t, err) // bot creation with permission th.AddPermissionToRole(model.PermissionCreateBot.Id, model.TeamUserRoleId) th.App.UpdateUserRoles(th.Context, th.BasicUser.Id, model.TeamUserRoleId+" "+model.SystemUserRoleId, false) bot := &model.Bot{ Username: GenerateTestUsername(), DisplayName: "a bot", Description: "bot", UserId: model.NewId(), } createdBot, resp, err := th.Client.CreateBot(bot) require.NoError(t, err) CheckCreatedStatus(t, resp) defer th.App.PermanentDeleteBot(createdBot.UserId) channelBuBot, _, err := client.CreateDirectChannel(basicUser.Id, createdBot.UserId) require.NoError(t, err) // create 2 posts in channelBu, 1 in channelBu1, 3 in channelBu12 postsGenConfig := []map[string]interface{}{ { "chId": channelBuBu.Id, "postCount": 2, }, { "chId": channelBu1Bu1.Id, "postCount": 1, }, { "chId": channelBuBu1.Id, "postCount": 3, }, { "chId": channelBuBot.Id, "postCount": 4, }, } for _, postGen := range postsGenConfig { postCount := postGen["postCount"].(int) for i := 0; i < postCount; i++ { if postGen["chId"] == channelBu1Bu1.Id { th.LoginBasic2() client = th.Client userId := basicUser1.Id post := &model.Post{UserId: userId, ChannelId: postGen["chId"].(string), Message: "zz" + model.NewId() + "a"} _, _, err = client.CreatePost(post) require.NoError(t, err) } else { th.LoginBasic() client = th.Client userId := basicUser.Id post := &model.Post{UserId: userId, ChannelId: postGen["chId"].(string), Message: "zz" + model.NewId() + "a"} _, _, err = client.CreatePost(post) require.NoError(t, err) } } } // get top dms for bu t.Run("get top dms for basic user 1", func(t *testing.T) { th.LoginBasic() client = th.Client topDMs, _, topDmsErr := client.GetTopDMsForUserSince("today", 0, 100) require.NoError(t, topDmsErr) require.Len(t, topDMs.Items, 1) require.Equal(t, topDMs.Items[0].MessageCount, int64(3)) require.Equal(t, topDMs.Items[0].SecondParticipant.Id, basicUser1.Id) // test pagination topDMsPage0PerPage1, _, topDmsErr := client.GetTopDMsForUserSince("today", 0, 2) require.NoError(t, topDmsErr) require.Len(t, topDMsPage0PerPage1.Items, 1) require.Equal(t, topDMsPage0PerPage1.HasNext, false) require.Equal(t, topDMsPage0PerPage1.Items[0].SecondParticipant.Id, basicUser1.Id) }) // get top dms for bu1 t.Run("get top dms for basic user 2", func(t *testing.T) { th.LoginBasic2() client = th.Client topDMs, _, topDmsErr := client.GetTopDMsForUserSince("today", 0, 100) require.NoError(t, topDmsErr) require.Len(t, topDMs.Items, 1) require.Equal(t, topDMs.Items[0].MessageCount, int64(3)) }) // deactivate basicuser1 _, err = th.Client.DeleteUser(basicUser1.Id) require.NoError(t, err) // deactivated users DMs should show in topDMs t.Run("get top dms for basic user 1", func(t *testing.T) { th.LoginBasic() client = th.Client topDMs, _, topDmsErr := client.GetTopDMsForUserSince("today", 0, 100) require.NoError(t, topDmsErr) require.Len(t, topDMs.Items, 1) require.Equal(t, topDMs.Items[0].MessageCount, int64(3)) }) } func TestNewTeamMembersSince(t *testing.T) { th := Setup(t).InitBasic() defer th.TearDown() th.LoginBasic() team := th.CreateTeam() t.Run("accepts only starter or professional license skus", func(t *testing.T) { _, resp, _ := th.Client.GetNewTeamMembersSince(team.Id, model.TimeRangeToday, 0, 5) CheckNotImplementedStatus(t, resp) th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuE10)) _, resp, _ = th.Client.GetNewTeamMembersSince(team.Id, model.TimeRangeToday, 0, 5) CheckNotImplementedStatus(t, resp) th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuE20)) _, resp, _ = th.Client.GetNewTeamMembersSince(team.Id, model.TimeRangeToday, 0, 5) CheckNotImplementedStatus(t, resp) th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuProfessional)) _, resp, err := th.Client.GetNewTeamMembersSince(team.Id, model.TimeRangeToday, 0, 5) require.NoError(t, err) CheckOKStatus(t, resp) th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuEnterprise)) _, resp, err = th.Client.GetNewTeamMembersSince(team.Id, model.TimeRangeToday, 0, 5) require.NoError(t, err) CheckOKStatus(t, resp) }) t.Run("rejects guests", func(t *testing.T) { _, resp, err := th.Client.GetNewTeamMembersSince(team.Id, model.TimeRangeToday, 0, 5) require.NoError(t, err) CheckOKStatus(t, resp) th.App.DemoteUserToGuest(th.Context, th.BasicUser) defer th.App.PromoteGuestToUser(th.Context, th.BasicUser, "") _, resp, _ = th.Client.GetNewTeamMembersSince(team.Id, model.TimeRangeToday, 0, 5) CheckNotImplementedStatus(t, resp) }) t.Run("includes all data for the user", func(t *testing.T) { checkUser := func(ntm *model.NewTeamMember, hasProfilePicture bool) { require.Equal(t, th.BasicUser.Id, ntm.Id) require.Equal(t, th.BasicUser.Username, ntm.Username) require.Equal(t, th.BasicUser.FirstName, ntm.FirstName) require.Equal(t, th.BasicUser.LastName, ntm.LastName) require.Equal(t, th.BasicUser.Position, ntm.Position) require.Equal(t, th.BasicUser.Nickname, ntm.Nickname) member, err := th.App.GetTeamMember(team.Id, th.BasicUser.Id) require.Nil(t, err) require.Equal(t, member.CreateAt, ntm.CreateAt) if hasProfilePicture { require.Truef(t, ntm.LastPictureUpdate > int64(0), "should be greater than 0, but was %d", ntm.LastPictureUpdate) } else { require.Equal(t, int64(0), ntm.LastPictureUpdate) } } th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuProfessional)) list, resp, err := th.Client.GetNewTeamMembersSince(team.Id, model.TimeRangeToday, 0, 5) require.NoError(t, err) CheckOKStatus(t, resp) checkUser(list.Items[0], false) data, err := testutils.ReadTestFile("test.png") require.NoError(t, err) _, err = th.Client.SetProfileImage(th.BasicUser.Id, data) require.NoError(t, err) list, resp, err = th.Client.GetNewTeamMembersSince(team.Id, model.TimeRangeToday, 0, 5) require.NoError(t, err) CheckOKStatus(t, resp) checkUser(list.Items[0], true) }) t.Run("implements pagination", func(t *testing.T) { // check the first page of results list, resp, err := th.Client.GetNewTeamMembersSince(team.Id, model.TimeRangeToday, 0, 2) require.NoError(t, err) CheckOKStatus(t, resp) require.Equal(t, int(list.TotalCount), 1) require.Len(t, list.Items, 1) require.False(t, list.HasNext) // check the 2nd page list, resp, err = th.Client.GetNewTeamMembersSince(team.Id, model.TimeRangeToday, 1, 2) require.NoError(t, err) CheckOKStatus(t, resp) require.GreaterOrEqual(t, len(list.Items), 0) // add a few new team members and re-test the pagination user := th.CreateUser() _, appErr := th.App.AddTeamMember(th.Context, team.Id, th.BasicUser2.Id) require.Nil(t, appErr) _, appErr = th.App.AddTeamMember(th.Context, team.Id, user.Id) require.Nil(t, appErr) list, resp, err = th.Client.GetNewTeamMembersSince(team.Id, model.TimeRangeToday, 0, 2) require.NoError(t, err) CheckOKStatus(t, resp) require.Equal(t, 3, int(list.TotalCount)) require.Len(t, list.Items, 2) require.True(t, list.HasNext) list, resp, err = th.Client.GetNewTeamMembersSince(team.Id, model.TimeRangeToday, 1, 2) require.NoError(t, err) CheckOKStatus(t, resp) require.Equal(t, int(list.TotalCount), 3) require.Len(t, list.Items, 1) require.False(t, list.HasNext) }) t.Run("get-new-team-members-since invalid license", func(t *testing.T) { th.App.Srv().SetLicense(model.NewTestLicense("")) _, resp, err := th.Client.GetNewTeamMembersSince(team.Id, model.TimeRangeToday, 0, 2) assert.Error(t, err) CheckNotImplementedStatus(t, resp) }) }