* removed server side

* Updated store layer

* unused import

* Updated autogenerated code template

* Updated tests

* lint fix

* unused translations

* webapp side

* Updated i18n

* lint fix:

* type fix

* Updated snapshots

* Removed insights from API specs

* updated e2e

* Updated e2e tests

* Updated e2e tests

* Removed insights tests

* Removed Insights as possible channel to load in sidebar from test

* Removed more insights tests

* More e2e fixed

* More cleanup

* Lint

* More cleanup in client4 and boards api

* More cleanup

* Fixes

* lint fix

---------

Co-authored-by: maria.nunez <maria.nunez@mattermost.com>
Co-authored-by: Mattermost Build <build@mattermost.com>
Этот коммит содержится в:
Harshil Sharma
2023-07-25 12:34:38 +05:30
коммит произвёл GitHub
родитель e37459cd00
Коммит 26617fcbdc
192 изменённых файлов: 47 добавлений и 19885 удалений

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

@@ -285,12 +285,6 @@ type AppIface interface {
// PopulateWebConnConfig checks if the connection id already exists in the hub,
// and if so, accordingly populates the other fields of the webconn.
PopulateWebConnConfig(s *model.Session, cfg *platform.WebConnConfig, seqVal string) (*platform.WebConnConfig, error)
// PostCountsByDuration returns the post counts for the given channels, grouped by day, starting at the given time.
// Unless one is specifically itending to omit results from part of the calendar day, it will typically makes the most sense to
// use a sinceUnixMillis parameter value as returned by model.GetStartOfDayMillis.
//
// WARNING: PostCountsByDuration PERFORMS NO AUTHORIZATION CHECKS ON THE GIVEN CHANNELS.
PostCountsByDuration(c request.CTX, channelIDs []string, sinceUnixMillis int64, userID *string, grouping model.PostCountGrouping, groupingLocation *time.Location) ([]*model.DurationPostCount, *model.AppError)
// PromoteGuestToUser Convert user's roles and all his membership's roles from
// guest roles to regular user roles.
PromoteGuestToUser(c *request.Context, user *model.User, requestorId string) *model.AppError
@@ -696,7 +690,6 @@ type AppIface interface {
GetMemberCountsByGroup(ctx context.Context, channelID string, includeTimezones bool) ([]*model.ChannelMemberCountByGroup, *model.AppError)
GetMessageForNotification(post *model.Post, translateFunc i18n.TranslateFunc) string
GetMultipleEmojiByName(c request.CTX, names []string) ([]*model.Emoji, *model.AppError)
GetNewTeamMembersSince(c request.CTX, teamID string, opts *model.InsightsOpts) (*model.NewTeamMembersList, int64, *model.AppError)
GetNewUsersForTeamPage(teamID string, page, perPage int, asAdmin bool, viewRestrictions *model.ViewUsersRestrictions) ([]*model.User, *model.AppError)
GetNextPostIdFromPostList(postList *model.PostList, collapsedThreads bool) string
GetNotificationNameFormat(user *model.User) string
@@ -817,15 +810,6 @@ type AppIface interface {
GetThreadMembershipsForUser(userID, teamID string) ([]*model.ThreadMembership, error)
GetThreadsForUser(userID, teamID string, options model.GetUserThreadsOpts) (*model.Threads, *model.AppError)
GetTokenById(token string) (*model.Token, *model.AppError)
GetTopChannelsForTeamSince(c request.CTX, teamID, userID string, opts *model.InsightsOpts) (*model.TopChannelList, *model.AppError)
GetTopChannelsForUserSince(c request.CTX, userID, teamID string, opts *model.InsightsOpts) (*model.TopChannelList, *model.AppError)
GetTopDMsForUserSince(userID string, opts *model.InsightsOpts) (*model.TopDMList, *model.AppError)
GetTopInactiveChannelsForTeamSince(c request.CTX, teamID, userID string, opts *model.InsightsOpts) (*model.TopInactiveChannelList, *model.AppError)
GetTopInactiveChannelsForUserSince(c request.CTX, teamID, userID string, opts *model.InsightsOpts) (*model.TopInactiveChannelList, *model.AppError)
GetTopReactionsForTeamSince(teamID string, userID string, opts *model.InsightsOpts) (*model.TopReactionList, *model.AppError)
GetTopReactionsForUserSince(userID string, teamID string, opts *model.InsightsOpts) (*model.TopReactionList, *model.AppError)
GetTopThreadsForTeamSince(c request.CTX, teamID, userID string, opts *model.InsightsOpts) (*model.TopThreadList, *model.AppError)
GetTopThreadsForUserSince(c request.CTX, teamID, userID string, opts *model.InsightsOpts) (*model.TopThreadList, *model.AppError)
GetTrueUpProfile() (map[string]any, error)
GetUploadSession(c request.CTX, uploadId string) (*model.UploadSession, *model.AppError)
GetUploadSessionsForUser(userID string) ([]*model.UploadSession, *model.AppError)

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

@@ -10,7 +10,6 @@ import (
"fmt"
"net/http"
"strings"
"time"
"github.com/mattermost/mattermost/server/public/model"
"github.com/mattermost/mattermost/server/public/plugin"
@@ -3518,66 +3517,3 @@ func (s *Server) getDirectChannel(c request.CTX, userID, otherUserID string) (*m
return channel, nil
}
func (a *App) GetTopChannelsForTeamSince(c request.CTX, teamID, userID string, opts *model.InsightsOpts) (*model.TopChannelList, *model.AppError) {
if !a.Config().FeatureFlags.InsightsEnabled {
return nil, model.NewAppError("GetTopChannelsForTeamSince", "api.insights.feature_disabled", nil, "", http.StatusNotImplemented)
}
topChannels, err := a.Srv().Store().Channel().GetTopChannelsForTeamSince(teamID, userID, opts.StartUnixMilli, opts.Page*opts.PerPage, opts.PerPage)
if err != nil {
return nil, model.NewAppError("GetTopChannelsForTeamSince", model.NoTranslation, nil, "", http.StatusInternalServerError).Wrap(err)
}
return topChannels, nil
}
func (a *App) GetTopChannelsForUserSince(c request.CTX, userID, teamID string, opts *model.InsightsOpts) (*model.TopChannelList, *model.AppError) {
if !a.Config().FeatureFlags.InsightsEnabled {
return nil, model.NewAppError("GetTopChannelsForUserSince", "api.insights.feature_disabled", nil, "", http.StatusNotImplemented)
}
topChannels, err := a.Srv().Store().Channel().GetTopChannelsForUserSince(userID, teamID, opts.StartUnixMilli, opts.Page*opts.PerPage, opts.PerPage)
if err != nil {
return nil, model.NewAppError("GetTopChannelsForUserSince", model.NoTranslation, nil, "", http.StatusInternalServerError).Wrap(err)
}
return topChannels, nil
}
// PostCountsByDuration returns the post counts for the given channels, grouped by day, starting at the given time.
// Unless one is specifically itending to omit results from part of the calendar day, it will typically makes the most sense to
// use a sinceUnixMillis parameter value as returned by model.GetStartOfDayMillis.
//
// WARNING: PostCountsByDuration PERFORMS NO AUTHORIZATION CHECKS ON THE GIVEN CHANNELS.
func (a *App) PostCountsByDuration(c request.CTX, channelIDs []string, sinceUnixMillis int64, userID *string, grouping model.PostCountGrouping, groupingLocation *time.Location) ([]*model.DurationPostCount, *model.AppError) {
if !a.Config().FeatureFlags.InsightsEnabled {
return nil, model.NewAppError("PostCountsByDuration", "api.insights.feature_disabled", nil, "", http.StatusNotImplemented)
}
postCountByDay, err := a.Srv().Store().Channel().PostCountsByDuration(channelIDs, sinceUnixMillis, userID, grouping, groupingLocation)
if err != nil {
return nil, model.NewAppError("PostCountsByDuration", model.NoTranslation, nil, "", http.StatusInternalServerError).Wrap(err)
}
return postCountByDay, nil
}
func (a *App) GetTopInactiveChannelsForTeamSince(c request.CTX, teamID, userID string, opts *model.InsightsOpts) (*model.TopInactiveChannelList, *model.AppError) {
if !a.Config().FeatureFlags.InsightsEnabled {
return nil, model.NewAppError("GetTopChannelsForTeamSince", "api.insights.feature_disabled", nil, "", http.StatusNotImplemented)
}
topChannels, err := a.Srv().Store().Channel().GetTopInactiveChannelsForTeamSince(teamID, userID, opts.StartUnixMilli, opts.Page*opts.PerPage, opts.PerPage)
if err != nil {
return nil, model.NewAppError("GetTopInactiveChannelsForTeamSince", model.NoTranslation, nil, "", http.StatusInternalServerError).Wrap(err)
}
return topChannels, nil
}
func (a *App) GetTopInactiveChannelsForUserSince(c request.CTX, teamID, userID string, opts *model.InsightsOpts) (*model.TopInactiveChannelList, *model.AppError) {
if !a.Config().FeatureFlags.InsightsEnabled {
return nil, model.NewAppError("GetTopChannelsForUserSince", "api.insights.feature_disabled", nil, "", http.StatusNotImplemented)
}
topChannels, err := a.Srv().Store().Channel().GetTopInactiveChannelsForUserSince(teamID, userID, opts.StartUnixMilli, opts.Page*opts.PerPage, opts.PerPage)
if err != nil {
return nil, model.NewAppError("GetTopInactiveChannelsForUserSince", model.NoTranslation, nil, "", http.StatusInternalServerError).Wrap(err)
}
return topChannels, nil
}

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

@@ -12,7 +12,6 @@ import (
"strings"
"sync"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
@@ -2495,523 +2494,3 @@ func TestIsCRTEnabledForUser(t *testing.T) {
})
}
}
func TestGetTopChannelsForTeamSince(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
th.ConfigStore.SetReadOnlyFF(false)
defer th.ConfigStore.SetReadOnlyFF(true)
th.App.UpdateConfig(func(cfg *model.Config) { cfg.FeatureFlags.InsightsEnabled = true })
channel2 := th.CreateChannel(th.Context, th.BasicTeam)
// add a bot post to ensure it's not counted
_, err := th.Server.Store().Post().Save(&model.Post{
Message: "hello from a bot",
ChannelId: channel2.Id,
UserId: th.BasicUser.Id,
Props: model.StringInterface{
"from_bot": true,
},
})
require.NoError(t, err)
channel3 := th.CreatePrivateChannel(th.Context, th.BasicTeam)
// add a webhook post to ensure it's not counted
_, err = th.Server.Store().Post().Save(&model.Post{
Message: "hello from a webhook",
ChannelId: channel3.Id,
UserId: th.BasicUser.Id,
Props: model.StringInterface{
"from_webhook": true,
},
})
require.NoError(t, err)
// add an oauth app post to ensure it's not counted
_, err = th.Server.Store().Post().Save(&model.Post{
Message: "hello from an ouath app",
ChannelId: channel3.Id,
UserId: th.BasicUser.Id,
Props: model.StringInterface{
"from_oauth_app": true,
},
})
require.NoError(t, err)
// add a plugin post to ensure it's not counted
_, err = th.Server.Store().Post().Save(&model.Post{
Message: "hello from a plugin",
ChannelId: channel3.Id,
UserId: th.BasicUser.Id,
Props: model.StringInterface{
"from_plugin": true,
},
})
require.NoError(t, err)
// add a system post to ensure it's not counted
_, err = th.Server.Store().Post().Save(&model.Post{
Message: "system message",
Type: "system_join_channel",
ChannelId: channel3.Id,
UserId: th.BasicUser.Id,
Props: model.StringInterface{
"from_oauth_app": true,
},
})
require.NoError(t, err)
channel4 := th.CreatePrivateChannel(th.Context, th.BasicTeam)
channel5 := th.CreateChannel(th.Context, th.BasicTeam)
channel6 := th.CreatePrivateChannel(th.Context, th.BasicTeam)
th.AddUserToChannel(th.BasicUser, channel2)
th.AddUserToChannel(th.BasicUser, channel3)
th.AddUserToChannel(th.BasicUser, channel4)
th.AddUserToChannel(th.BasicUser, channel5)
th.AddUserToChannel(th.BasicUser, channel6)
channels := [6]*model.Channel{th.BasicChannel, channel2, channel3, channel4, channel5, channel6}
i := len(channels)
for _, channel := range channels {
for j := i; j > 0; j-- {
th.CreatePost(channel)
}
i--
}
expectedTopChannels := []struct {
ID string
MessageCount int64
}{
{ID: th.BasicChannel.Id, MessageCount: 7},
{ID: channel2.Id, MessageCount: 5},
{ID: channel3.Id, MessageCount: 4},
{ID: channel4.Id, MessageCount: 3},
{ID: channel5.Id, MessageCount: 2},
}
timeRange, _ := model.GetStartOfDayForTimeRange(model.TimeRangeToday, time.Now().Location())
t.Run("get-top-channels-for-team-since", func(t *testing.T) {
topChannels, err := th.App.GetTopChannelsForTeamSince(th.Context, th.BasicChannel.TeamId, th.BasicUser.Id, &model.InsightsOpts{StartUnixMilli: timeRange.UnixMilli(), Page: 0, PerPage: 5})
require.Nil(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 = th.App.GetTopChannelsForTeamSince(th.Context, th.BasicChannel.TeamId, th.BasicUser.Id, &model.InsightsOpts{StartUnixMilli: timeRange.UnixMilli(), Page: 1, PerPage: 5})
require.Nil(t, err)
assert.Equal(t, channel6.Id, topChannels.Items[0].ID)
assert.Equal(t, int64(1), topChannels.Items[0].MessageCount)
})
}
func TestGetTopChannelsForUserSince(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
th.ConfigStore.SetReadOnlyFF(false)
defer th.ConfigStore.SetReadOnlyFF(true)
th.App.UpdateConfig(func(cfg *model.Config) { cfg.FeatureFlags.InsightsEnabled = true })
channel2 := th.CreateChannel(th.Context, th.BasicTeam)
// add a bot post to ensure it's not counted
_, err := th.Server.Store().Post().Save(&model.Post{
Message: "hello from a bot",
ChannelId: channel2.Id,
UserId: th.BasicUser.Id,
Props: model.StringInterface{
"from_bot": true,
},
})
require.NoError(t, err)
channel3 := th.CreatePrivateChannel(th.Context, th.BasicTeam)
// add a webhook post to ensure it's not counted
_, err = th.Server.Store().Post().Save(&model.Post{
Message: "hello from a webhook",
ChannelId: channel3.Id,
UserId: th.BasicUser.Id,
Props: model.StringInterface{
"from_webhook": true,
},
})
require.NoError(t, err)
channel4 := th.CreatePrivateChannel(th.Context, th.BasicTeam)
channel5 := th.CreateChannel(th.Context, th.BasicTeam)
channel6 := th.CreatePrivateChannel(th.Context, th.BasicTeam)
th.AddUserToChannel(th.BasicUser, channel2)
th.AddUserToChannel(th.BasicUser, channel3)
th.AddUserToChannel(th.BasicUser, channel4)
th.AddUserToChannel(th.BasicUser, channel5)
th.AddUserToChannel(th.BasicUser, channel6)
channels := [6]*model.Channel{th.BasicChannel, channel2, channel3, channel4, channel5, channel6}
i := len(channels)
for _, channel := range channels {
for j := i; j > 0; j-- {
th.CreatePost(channel)
}
i--
}
expectedTopChannels := []struct {
ID string
MessageCount int64
}{
{ID: th.BasicChannel.Id, MessageCount: 7},
{ID: channel2.Id, MessageCount: 5},
{ID: channel3.Id, MessageCount: 4},
{ID: channel4.Id, MessageCount: 3},
{ID: channel5.Id, MessageCount: 2},
}
timeRange, _ := model.GetStartOfDayForTimeRange(model.TimeRangeToday, time.Now().Location())
t.Run("get-top-channels-for-user-since", func(t *testing.T) {
topChannels, err := th.App.GetTopChannelsForUserSince(th.Context, th.BasicUser.Id, "", &model.InsightsOpts{StartUnixMilli: timeRange.UnixMilli(), Page: 0, PerPage: 5})
require.Nil(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 = th.App.GetTopChannelsForUserSince(th.Context, th.BasicUser.Id, th.BasicChannel.TeamId, &model.InsightsOpts{StartUnixMilli: timeRange.UnixMilli(), Page: 1, PerPage: 5})
require.Nil(t, err)
assert.Equal(t, channel6.Id, topChannels.Items[0].ID)
assert.Equal(t, int64(1), topChannels.Items[0].MessageCount)
})
}
func TestPostCountsByDuration(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
th.ConfigStore.SetReadOnlyFF(false)
defer th.ConfigStore.SetReadOnlyFF(true)
th.App.UpdateConfig(func(cfg *model.Config) { cfg.FeatureFlags.InsightsEnabled = true })
channel2 := th.CreateChannel(th.Context, th.BasicTeam)
channel3 := th.CreatePrivateChannel(th.Context, th.BasicTeam)
channel4 := th.CreatePrivateChannel(th.Context, th.BasicTeam)
channel5 := th.CreateChannel(th.Context, th.BasicTeam)
channel6 := th.CreatePrivateChannel(th.Context, th.BasicTeam)
defer func() {
th.App.PermanentDeleteChannel(th.Context, channel2)
th.App.PermanentDeleteChannel(th.Context, channel3)
th.App.PermanentDeleteChannel(th.Context, channel4)
th.App.PermanentDeleteChannel(th.Context, channel5)
th.App.PermanentDeleteChannel(th.Context, channel6)
}()
th.AddUserToChannel(th.BasicUser, channel2)
th.AddUserToChannel(th.BasicUser, channel3)
th.AddUserToChannel(th.BasicUser, channel4)
th.AddUserToChannel(th.BasicUser, channel5)
th.AddUserToChannel(th.BasicUser, channel6)
channels := [6]*model.Channel{th.BasicChannel, channel2, channel3, channel4, channel5, channel6}
channelIDs := []string{th.BasicChannel.Id, channel2.Id, channel3.Id, channel4.Id, channel5.Id, channel6.Id}
i := len(channels)
for ci, channel := range channels {
for j := i; j > 0; j-- {
d1 := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC).AddDate(0, 0, ci)
d2 := time.Date(2009, time.November, 10, 9, 0, 0, 0, time.UTC).AddDate(0, 0, ci)
_, err := th.App.CreatePost(th.Context, &model.Post{
UserId: th.BasicUser.Id,
ChannelId: channel.Id,
CreateAt: d1.Unix() * 1000,
}, channel, false, false)
require.Nil(t, err)
_, err = th.App.CreatePost(th.Context, &model.Post{
UserId: th.BasicUser2.Id,
ChannelId: channel.Id,
CreateAt: d2.Unix() * 1000,
}, channel, false, false)
require.Nil(t, err)
}
i--
}
expectedDayGrouping := map[string]map[string]int{
"2009-11-10": {
th.BasicChannel.Id: 6,
},
"2009-11-11": {
channel2.Id: 5,
},
"2009-11-12": {
channel3.Id: 4,
},
"2009-11-13": {
channel4.Id: 3,
},
"2009-11-14": {
channel5.Id: 2,
},
"2009-11-15": {
channel6.Id: 1,
},
}
expectedHourGrouping := map[string]map[string]int{
"2009-11-15T09": {
channel6.Id: 1,
},
"2009-11-15T23": {
channel6.Id: 1,
},
}
sinceUnixMillis := time.Date(2009, time.November, 9, 23, 0, 0, 0, time.UTC).UnixMilli()
t.Run("get-post-counts-by-day scoped by user, grouped by day", func(t *testing.T) {
dailyPostCount, err := th.App.PostCountsByDuration(th.Context, channelIDs, sinceUnixMillis, &th.BasicUser.Id, model.PostsByDay, time.Now().UTC().Location())
require.Nil(t, err)
require.GreaterOrEqual(t, len(dailyPostCount), 6)
for _, item := range dailyPostCount {
if strings.HasPrefix(item.Duration, "2009") {
expectedCount := expectedDayGrouping[item.Duration][item.ChannelID]
assert.Equal(t, expectedCount, item.PostCount)
}
}
})
t.Run("get-post-counts-by-day all users, grouped by day", func(t *testing.T) {
dailyPostCount, err := th.App.PostCountsByDuration(th.Context, channelIDs, sinceUnixMillis, nil, model.PostsByDay, time.Now().UTC().Location())
require.Nil(t, err)
require.GreaterOrEqual(t, len(dailyPostCount), 6)
for _, item := range dailyPostCount {
if strings.HasPrefix(item.Duration, "2009") {
expectedCount := expectedDayGrouping[item.Duration][item.ChannelID]
assert.Equal(t, expectedCount*2, item.PostCount)
}
}
})
t.Run("get-post-counts-by-day all users, grouped by hour", func(t *testing.T) {
oneDaySince := time.Date(2009, time.November, 14, 23, 0, 0, 0, time.UTC).UnixMilli()
dailyPostCount, err := th.App.PostCountsByDuration(th.Context, channelIDs, oneDaySince, nil, model.PostsByHour, time.Now().UTC().Location())
require.Nil(t, err)
require.GreaterOrEqual(t, len(dailyPostCount), 1)
for _, item := range dailyPostCount {
if strings.HasPrefix(item.Duration, "2009") {
expectedCount := expectedHourGrouping[item.Duration][item.ChannelID]
assert.Equal(t, expectedCount, item.PostCount)
}
}
})
}
// Top inactive channels
func TestGetTopInactiveChannelsForTeamSince(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
th.ConfigStore.SetReadOnlyFF(false)
defer th.ConfigStore.SetReadOnlyFF(true)
th.App.UpdateConfig(func(cfg *model.Config) { cfg.FeatureFlags.InsightsEnabled = true })
channel2 := th.CreateChannel(th.Context, th.BasicTeam, WithCreateAt(1))
channel3 := th.CreateChannel(th.Context, th.BasicTeam, WithCreateAt(1))
channel4 := th.CreatePrivateChannel(th.Context, th.BasicTeam, WithCreateAt(1))
channel5 := th.CreateChannel(th.Context, th.BasicTeam, WithCreateAt(1))
channel6 := th.CreatePrivateChannel(th.Context, th.BasicTeam, WithCreateAt(1))
th.AddUserToChannel(th.BasicUser, channel2)
th.AddUserToChannel(th.BasicUser, channel3)
th.AddUserToChannel(th.BasicUser, channel4)
th.AddUserToChannel(th.BasicUser, channel5)
th.AddUserToChannel(th.BasicUser, channel6)
// delete offtopic, town square, 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)
// add a bot post to ensure it's counted
_, err := th.Server.Store().Post().Save(&model.Post{
Message: "hello from a bot",
ChannelId: channel2.Id,
UserId: th.BasicUser.Id,
Props: model.StringInterface{
"from_bot": true,
},
})
require.NoError(t, err)
// add a webhook post to ensure it's counted
_, err = th.Server.Store().Post().Save(&model.Post{
Message: "hello from a webhook",
ChannelId: channel3.Id,
UserId: th.BasicUser.Id,
Props: model.StringInterface{
"from_webhook": true,
},
})
require.NoError(t, err)
channels := [5]*model.Channel{channel2, channel3, channel4, channel5, channel6}
i := len(channels)
for _, channel := range channels {
for j := i; j > 0; j-- {
th.CreatePost(channel)
}
i--
}
expectedTopChannels := []struct {
ID string
MessageCount int64
}{
{ID: channel6.Id, MessageCount: 1},
{ID: channel5.Id, MessageCount: 2},
{ID: channel4.Id, MessageCount: 3},
{ID: channel3.Id, MessageCount: 5},
{ID: channel2.Id, MessageCount: 6},
}
timeRange, _ := model.GetStartOfDayForTimeRange(model.TimeRangeToday, time.Now().Location())
t.Run("get-top-channels-for-team-since", func(t *testing.T) {
topChannels, err := th.App.GetTopInactiveChannelsForTeamSince(th.Context, th.BasicChannel.TeamId, th.BasicUser.Id, &model.InsightsOpts{StartUnixMilli: timeRange.UnixMilli(), Page: 0, PerPage: 5})
require.Nil(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 = th.App.GetTopInactiveChannelsForTeamSince(th.Context, th.BasicChannel.TeamId, th.BasicUser.Id, &model.InsightsOpts{StartUnixMilli: timeRange.UnixMilli(), Page: 1, PerPage: 4})
require.Nil(t, err)
assert.Equal(t, channel2.Id, topChannels.Items[0].ID)
assert.Equal(t, int64(6), topChannels.Items[0].MessageCount)
// it simulates channel being created recently
_ = th.CreatePrivateChannel(th.Context, th.BasicTeam)
topChannels, err = th.App.GetTopInactiveChannelsForTeamSince(th.Context, th.BasicChannel.TeamId, th.BasicUser.Id, &model.InsightsOpts{StartUnixMilli: timeRange.UnixMilli(), Page: 0, PerPage: 6})
require.Nil(t, err)
assert.Equal(t, 5, len(topChannels.Items))
})
}
func TestGetTopInactiveChannelsForUserSince(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
th.ConfigStore.SetReadOnlyFF(false)
defer th.ConfigStore.SetReadOnlyFF(true)
th.App.UpdateConfig(func(cfg *model.Config) { cfg.FeatureFlags.InsightsEnabled = true })
// delete offtopic, town-square, th.basicchannel channels - 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)
channel2 := th.CreateChannel(th.Context, th.BasicTeam, WithCreateAt(1))
// add a bot post to ensure it's counted
_, err := th.Server.Store().Post().Save(&model.Post{
Message: "hello from a bot",
ChannelId: channel2.Id,
UserId: th.BasicUser.Id,
Props: model.StringInterface{
"from_bot": true,
},
})
require.NoError(t, err)
channel3 := th.CreatePrivateChannel(th.Context, th.BasicTeam, WithCreateAt(1))
// add a webhook post to ensure it's counted
_, err = th.Server.Store().Post().Save(&model.Post{
Message: "hello from a webhook",
ChannelId: channel3.Id,
UserId: th.BasicUser.Id,
Props: model.StringInterface{
"from_webhook": true,
},
})
require.NoError(t, err)
channel4 := th.CreatePrivateChannel(th.Context, th.BasicTeam, WithCreateAt(1))
channel5 := th.CreateChannel(th.Context, th.BasicTeam, WithCreateAt(1))
channel6 := th.CreatePrivateChannel(th.Context, th.BasicTeam, WithCreateAt(1))
th.AddUserToChannel(th.BasicUser, channel2)
th.AddUserToChannel(th.BasicUser, channel3)
th.AddUserToChannel(th.BasicUser, channel4)
th.AddUserToChannel(th.BasicUser, channel5)
th.AddUserToChannel(th.BasicUser, channel6)
channels := [5]*model.Channel{channel2, channel3, channel4, channel5, channel6}
i := len(channels)
for _, channel := range channels {
for j := i; j > 0; j-- {
th.CreatePost(channel)
}
i--
}
expectedTopChannels := []struct {
ID string
MessageCount int64
}{
{ID: channel6.Id, MessageCount: 1},
{ID: channel5.Id, MessageCount: 2},
{ID: channel4.Id, MessageCount: 3},
{ID: channel3.Id, MessageCount: 5},
{ID: channel2.Id, MessageCount: 6},
}
timeRange, _ := model.GetStartOfDayForTimeRange(model.TimeRangeToday, time.Now().Location())
t.Run("get-top-channels-for-user-since", func(t *testing.T) {
topChannels, err := th.App.GetTopInactiveChannelsForUserSince(th.Context, th.BasicChannel.TeamId, th.BasicUser.Id, &model.InsightsOpts{StartUnixMilli: timeRange.UnixMilli(), Page: 0, PerPage: 4})
require.Nil(t, err)
require.Equal(t, len(topChannels.Items), 4)
for i, channel := range topChannels.Items {
assert.Equal(t, expectedTopChannels[i].ID, channel.ID)
assert.Equal(t, expectedTopChannels[i].MessageCount, channel.MessageCount)
}
topChannels, err = th.App.GetTopInactiveChannelsForUserSince(th.Context, th.BasicChannel.TeamId, th.BasicUser.Id, &model.InsightsOpts{StartUnixMilli: timeRange.UnixMilli(), Page: 1, PerPage: 4})
require.Nil(t, err)
require.Equal(t, len(topChannels.Items), 1)
assert.Equal(t, channel2.Id, topChannels.Items[0].ID)
assert.Equal(t, int64(6), topChannels.Items[0].MessageCount)
})
}

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

@@ -7381,28 +7381,6 @@ func (a *OpenTracingAppLayer) GetMultipleEmojiByName(c request.CTX, names []stri
return resultVar0, resultVar1
}
func (a *OpenTracingAppLayer) GetNewTeamMembersSince(c request.CTX, teamID string, opts *model.InsightsOpts) (*model.NewTeamMembersList, int64, *model.AppError) {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetNewTeamMembersSince")
a.ctx = newCtx
a.app.Srv().Store().SetContext(newCtx)
defer func() {
a.app.Srv().Store().SetContext(origCtx)
a.ctx = origCtx
}()
defer span.Finish()
resultVar0, resultVar1, resultVar2 := a.app.GetNewTeamMembersSince(c, teamID, opts)
if resultVar2 != nil {
span.LogFields(spanlog.Error(resultVar2))
ext.Error.Set(span, true)
}
return resultVar0, resultVar1, resultVar2
}
func (a *OpenTracingAppLayer) GetNewUsersForTeamPage(teamID string, page int, perPage int, asAdmin bool, viewRestrictions *model.ViewUsersRestrictions) ([]*model.User, *model.AppError) {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetNewUsersForTeamPage")
@@ -10291,204 +10269,6 @@ func (a *OpenTracingAppLayer) GetTokenById(token string) (*model.Token, *model.A
return resultVar0, resultVar1
}
func (a *OpenTracingAppLayer) GetTopChannelsForTeamSince(c request.CTX, teamID string, userID string, opts *model.InsightsOpts) (*model.TopChannelList, *model.AppError) {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetTopChannelsForTeamSince")
a.ctx = newCtx
a.app.Srv().Store().SetContext(newCtx)
defer func() {
a.app.Srv().Store().SetContext(origCtx)
a.ctx = origCtx
}()
defer span.Finish()
resultVar0, resultVar1 := a.app.GetTopChannelsForTeamSince(c, teamID, userID, opts)
if resultVar1 != nil {
span.LogFields(spanlog.Error(resultVar1))
ext.Error.Set(span, true)
}
return resultVar0, resultVar1
}
func (a *OpenTracingAppLayer) GetTopChannelsForUserSince(c request.CTX, userID string, teamID string, opts *model.InsightsOpts) (*model.TopChannelList, *model.AppError) {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetTopChannelsForUserSince")
a.ctx = newCtx
a.app.Srv().Store().SetContext(newCtx)
defer func() {
a.app.Srv().Store().SetContext(origCtx)
a.ctx = origCtx
}()
defer span.Finish()
resultVar0, resultVar1 := a.app.GetTopChannelsForUserSince(c, userID, teamID, opts)
if resultVar1 != nil {
span.LogFields(spanlog.Error(resultVar1))
ext.Error.Set(span, true)
}
return resultVar0, resultVar1
}
func (a *OpenTracingAppLayer) GetTopDMsForUserSince(userID string, opts *model.InsightsOpts) (*model.TopDMList, *model.AppError) {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetTopDMsForUserSince")
a.ctx = newCtx
a.app.Srv().Store().SetContext(newCtx)
defer func() {
a.app.Srv().Store().SetContext(origCtx)
a.ctx = origCtx
}()
defer span.Finish()
resultVar0, resultVar1 := a.app.GetTopDMsForUserSince(userID, opts)
if resultVar1 != nil {
span.LogFields(spanlog.Error(resultVar1))
ext.Error.Set(span, true)
}
return resultVar0, resultVar1
}
func (a *OpenTracingAppLayer) GetTopInactiveChannelsForTeamSince(c request.CTX, teamID string, userID string, opts *model.InsightsOpts) (*model.TopInactiveChannelList, *model.AppError) {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetTopInactiveChannelsForTeamSince")
a.ctx = newCtx
a.app.Srv().Store().SetContext(newCtx)
defer func() {
a.app.Srv().Store().SetContext(origCtx)
a.ctx = origCtx
}()
defer span.Finish()
resultVar0, resultVar1 := a.app.GetTopInactiveChannelsForTeamSince(c, teamID, userID, opts)
if resultVar1 != nil {
span.LogFields(spanlog.Error(resultVar1))
ext.Error.Set(span, true)
}
return resultVar0, resultVar1
}
func (a *OpenTracingAppLayer) GetTopInactiveChannelsForUserSince(c request.CTX, teamID string, userID string, opts *model.InsightsOpts) (*model.TopInactiveChannelList, *model.AppError) {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetTopInactiveChannelsForUserSince")
a.ctx = newCtx
a.app.Srv().Store().SetContext(newCtx)
defer func() {
a.app.Srv().Store().SetContext(origCtx)
a.ctx = origCtx
}()
defer span.Finish()
resultVar0, resultVar1 := a.app.GetTopInactiveChannelsForUserSince(c, teamID, userID, opts)
if resultVar1 != nil {
span.LogFields(spanlog.Error(resultVar1))
ext.Error.Set(span, true)
}
return resultVar0, resultVar1
}
func (a *OpenTracingAppLayer) GetTopReactionsForTeamSince(teamID string, userID string, opts *model.InsightsOpts) (*model.TopReactionList, *model.AppError) {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetTopReactionsForTeamSince")
a.ctx = newCtx
a.app.Srv().Store().SetContext(newCtx)
defer func() {
a.app.Srv().Store().SetContext(origCtx)
a.ctx = origCtx
}()
defer span.Finish()
resultVar0, resultVar1 := a.app.GetTopReactionsForTeamSince(teamID, userID, opts)
if resultVar1 != nil {
span.LogFields(spanlog.Error(resultVar1))
ext.Error.Set(span, true)
}
return resultVar0, resultVar1
}
func (a *OpenTracingAppLayer) GetTopReactionsForUserSince(userID string, teamID string, opts *model.InsightsOpts) (*model.TopReactionList, *model.AppError) {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetTopReactionsForUserSince")
a.ctx = newCtx
a.app.Srv().Store().SetContext(newCtx)
defer func() {
a.app.Srv().Store().SetContext(origCtx)
a.ctx = origCtx
}()
defer span.Finish()
resultVar0, resultVar1 := a.app.GetTopReactionsForUserSince(userID, teamID, opts)
if resultVar1 != nil {
span.LogFields(spanlog.Error(resultVar1))
ext.Error.Set(span, true)
}
return resultVar0, resultVar1
}
func (a *OpenTracingAppLayer) GetTopThreadsForTeamSince(c request.CTX, teamID string, userID string, opts *model.InsightsOpts) (*model.TopThreadList, *model.AppError) {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetTopThreadsForTeamSince")
a.ctx = newCtx
a.app.Srv().Store().SetContext(newCtx)
defer func() {
a.app.Srv().Store().SetContext(origCtx)
a.ctx = origCtx
}()
defer span.Finish()
resultVar0, resultVar1 := a.app.GetTopThreadsForTeamSince(c, teamID, userID, opts)
if resultVar1 != nil {
span.LogFields(spanlog.Error(resultVar1))
ext.Error.Set(span, true)
}
return resultVar0, resultVar1
}
func (a *OpenTracingAppLayer) GetTopThreadsForUserSince(c request.CTX, teamID string, userID string, opts *model.InsightsOpts) (*model.TopThreadList, *model.AppError) {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetTopThreadsForUserSince")
a.ctx = newCtx
a.app.Srv().Store().SetContext(newCtx)
defer func() {
a.app.Srv().Store().SetContext(origCtx)
a.ctx = origCtx
}()
defer span.Finish()
resultVar0, resultVar1 := a.app.GetTopThreadsForUserSince(c, teamID, userID, opts)
if resultVar1 != nil {
span.LogFields(spanlog.Error(resultVar1))
ext.Error.Set(span, true)
}
return resultVar0, resultVar1
}
func (a *OpenTracingAppLayer) GetTotalUsersStats(viewRestrictions *model.ViewUsersRestrictions) (*model.UsersStats, *model.AppError) {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetTotalUsersStats")
@@ -13413,28 +13193,6 @@ func (a *OpenTracingAppLayer) PostAddToChannelMessage(c request.CTX, user *model
return resultVar0
}
func (a *OpenTracingAppLayer) PostCountsByDuration(c request.CTX, channelIDs []string, sinceUnixMillis int64, userID *string, grouping model.PostCountGrouping, groupingLocation *time.Location) ([]*model.DurationPostCount, *model.AppError) {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.PostCountsByDuration")
a.ctx = newCtx
a.app.Srv().Store().SetContext(newCtx)
defer func() {
a.app.Srv().Store().SetContext(origCtx)
a.ctx = origCtx
}()
defer span.Finish()
resultVar0, resultVar1 := a.app.PostCountsByDuration(c, channelIDs, sinceUnixMillis, userID, grouping, groupingLocation)
if resultVar1 != nil {
span.LogFields(spanlog.Error(resultVar1))
ext.Error.Set(span, true)
}
return resultVar0, resultVar1
}
func (a *OpenTracingAppLayer) PostPatchWithProxyRemovedFromImageURLs(patch *model.PostPatch) *model.PostPatch {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.PostPatchWithProxyRemovedFromImageURLs")

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

@@ -178,22 +178,17 @@ func TestPluginAPIGetUserPreferences(t *testing.T) {
preferences, err := api.GetPreferencesForUser(user1.Id)
require.Nil(t, err)
assert.Equal(t, 3, len(preferences))
assert.Equal(t, 2, len(preferences))
assert.Equal(t, user1.Id, preferences[0].UserId)
assert.Equal(t, model.PreferenceCategoryInsights, preferences[0].Category)
assert.Equal(t, model.PreferenceNameInsights, preferences[0].Name)
assert.Equal(t, "{\"insights_modal_viewed\":false}", preferences[0].Value)
assert.Equal(t, model.PreferenceRecommendedNextSteps, preferences[0].Category)
assert.Equal(t, "hide", preferences[0].Name)
assert.Equal(t, "false", preferences[0].Value)
assert.Equal(t, user1.Id, preferences[1].UserId)
assert.Equal(t, model.PreferenceRecommendedNextSteps, preferences[1].Category)
assert.Equal(t, "hide", preferences[1].Name)
assert.Equal(t, "false", preferences[1].Value)
assert.Equal(t, user1.Id, preferences[2].UserId)
assert.Equal(t, model.PreferenceCategoryTutorialSteps, preferences[2].Category)
assert.Equal(t, user1.Id, preferences[2].Name)
assert.Equal(t, "0", preferences[2].Value)
assert.Equal(t, model.PreferenceCategoryTutorialSteps, preferences[1].Category)
assert.Equal(t, user1.Id, preferences[1].Name)
assert.Equal(t, "0", preferences[1].Value)
}
func TestPluginAPIDeleteUserPreferences(t *testing.T) {
@@ -245,10 +240,9 @@ func TestPluginAPIDeleteUserPreferences(t *testing.T) {
require.Nil(t, err)
preferences, err = api.GetPreferencesForUser(user2.Id)
require.Nil(t, err)
assert.Equal(t, 3, len(preferences))
assert.Equal(t, model.PreferenceCategoryInsights, preferences[0].Category)
assert.Equal(t, model.PreferenceRecommendedNextSteps, preferences[1].Category)
assert.Equal(t, model.PreferenceCategoryTutorialSteps, preferences[2].Category)
assert.Equal(t, 2, len(preferences))
assert.Equal(t, model.PreferenceRecommendedNextSteps, preferences[0].Category)
assert.Equal(t, model.PreferenceCategoryTutorialSteps, preferences[1].Category)
}
func TestPluginAPIUpdateUserPreferences(t *testing.T) {
@@ -266,22 +260,16 @@ func TestPluginAPIUpdateUserPreferences(t *testing.T) {
preferences, err := api.GetPreferencesForUser(user1.Id)
require.Nil(t, err)
assert.Equal(t, 3, len(preferences))
assert.Equal(t, 2, len(preferences))
assert.Equal(t, user1.Id, preferences[0].UserId)
assert.Equal(t, model.PreferenceCategoryInsights, preferences[0].Category)
assert.Equal(t, model.PreferenceNameInsights, preferences[0].Name)
assert.Equal(t, "{\"insights_modal_viewed\":false}", preferences[0].Value)
assert.Equal(t, model.PreferenceRecommendedNextSteps, preferences[0].Category)
assert.Equal(t, "hide", preferences[0].Name)
assert.Equal(t, "false", preferences[0].Value)
assert.Equal(t, user1.Id, preferences[1].UserId)
assert.Equal(t, model.PreferenceRecommendedNextSteps, preferences[1].Category)
assert.Equal(t, "hide", preferences[1].Name)
assert.Equal(t, "false", preferences[1].Value)
assert.Equal(t, user1.Id, preferences[2].UserId)
assert.Equal(t, model.PreferenceCategoryTutorialSteps, preferences[2].Category)
assert.Equal(t, user1.Id, preferences[2].Name)
assert.Equal(t, "0", preferences[2].Value)
assert.Equal(t, model.PreferenceCategoryTutorialSteps, preferences[1].Category)
assert.Equal(t, user1.Id, preferences[1].Name)
assert.Equal(t, "0", preferences[1].Value)
preference := model.Preference{
Name: user1.Id,
@@ -296,8 +284,8 @@ func TestPluginAPIUpdateUserPreferences(t *testing.T) {
preferences, err = api.GetPreferencesForUser(user1.Id)
require.Nil(t, err)
assert.Equal(t, 4, len(preferences))
expectedCategories := []string{model.PreferenceCategoryTutorialSteps, model.PreferenceCategoryTheme, model.PreferenceRecommendedNextSteps, model.PreferenceCategoryInsights}
assert.Equal(t, 3, len(preferences))
expectedCategories := []string{model.PreferenceCategoryTutorialSteps, model.PreferenceCategoryTheme, model.PreferenceRecommendedNextSteps}
for _, pref := range preferences {
assert.Contains(t, expectedCategories, pref.Category)
assert.Equal(t, user1.Id, pref.UserId)

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

@@ -2045,49 +2045,6 @@ func (a *App) GetEditHistoryForPost(postID string) ([]*model.Post, *model.AppErr
return posts, nil
}
func (a *App) GetTopThreadsForTeamSince(c request.CTX, teamID, userID string, opts *model.InsightsOpts) (*model.TopThreadList, *model.AppError) {
if !a.Config().FeatureFlags.InsightsEnabled {
return nil, model.NewAppError("GetTopChannelsForTeamSince", "app.insights.feature_disabled", nil, "", http.StatusNotImplemented)
}
topThreads, err := a.Srv().Store().Thread().GetTopThreadsForTeamSince(teamID, userID, opts.StartUnixMilli, opts.Page*opts.PerPage, opts.PerPage)
if err != nil {
return nil, model.NewAppError("GetTopChannelsForTeamSince", "app.post.get_top_threads_for_team_since.app_error", nil, "", http.StatusInternalServerError).Wrap(err)
}
topThreadsWithEmbedAndImage, err := includeEmbedsAndImages(a, c, topThreads, userID)
if err != nil {
return nil, model.NewAppError("GetTopChannelsForTeamSince", "app.post.get_top_threads_for_team_since.app_error", nil, "", http.StatusInternalServerError).Wrap(err)
}
return topThreadsWithEmbedAndImage, nil
}
func (a *App) GetTopThreadsForUserSince(c request.CTX, teamID, userID string, opts *model.InsightsOpts) (*model.TopThreadList, *model.AppError) {
if !a.Config().FeatureFlags.InsightsEnabled {
return nil, model.NewAppError("GetTopChannelsForTeamSince", "app.insights.feature_disabled", nil, "", http.StatusNotImplemented)
}
topThreads, err := a.Srv().Store().Thread().GetTopThreadsForUserSince(teamID, userID, opts.StartUnixMilli, opts.Page*opts.PerPage, opts.PerPage)
if err != nil {
return nil, model.NewAppError("GetTopChannelsForTeamSince", "app.post.get_top_threads_for_team_since.app_error", nil, "", http.StatusInternalServerError).Wrap(err)
}
topThreadsWithEmbedAndImage, err := includeEmbedsAndImages(a, c, topThreads, userID)
if err != nil {
return nil, model.NewAppError("GetTopChannelsForUserSince", "app.post.get_top_threads_for_user_since.app_error", nil, "", http.StatusInternalServerError).Wrap(err)
}
return topThreadsWithEmbedAndImage, nil
}
func (a *App) GetTopDMsForUserSince(userID string, opts *model.InsightsOpts) (*model.TopDMList, *model.AppError) {
if !a.Config().FeatureFlags.InsightsEnabled {
return nil, model.NewAppError("GetTopDMsForUserSince", "app.insights.feature_disabled", nil, "", http.StatusNotImplemented)
}
topDMs, err := a.Srv().Store().Post().GetTopDMsForUserSince(userID, opts.StartUnixMilli, opts.Page*opts.PerPage, opts.PerPage)
if err != nil {
return nil, model.NewAppError("GetTopDMsForUserSince", "app.post.get_top_dms_for_user_since.app_error", nil, err.Error(), http.StatusInternalServerError)
}
return topDMs, nil
}
func (a *App) SetPostReminder(postID, userID string, targetTime int64) *model.AppError {
// Store the reminder in the DB
reminder := &model.PostReminder{
@@ -2285,15 +2242,3 @@ func (a *App) GetPostInfo(c request.CTX, postID string) (*model.PostInfo, *model
}
return &info, nil
}
func includeEmbedsAndImages(a *App, c request.CTX, topThreadList *model.TopThreadList, userID string) (*model.TopThreadList, error) {
for _, topThread := range topThreadList.Items {
topThread.Post = a.PreparePostForClientWithEmbedsAndImages(c, topThread.Post, false, false, true)
sanitizedPost, err := a.SanitizePostMetadataForUser(c, topThread.Post, userID)
if err != nil {
return nil, err
}
topThread.Post = sanitizedPost
}
return topThreadList, nil
}

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

@@ -3028,195 +3028,6 @@ func TestComputeLastAccessiblePostTime(t *testing.T) {
})
}
func TestGetTopThreadsForTeamSince(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
th.ConfigStore.SetReadOnlyFF(false)
defer th.ConfigStore.SetReadOnlyFF(true)
th.App.UpdateConfig(func(cfg *model.Config) { cfg.FeatureFlags.InsightsEnabled = true })
// create a public channel, a private channel
channelPublic := th.CreateChannel(th.Context, th.BasicTeam)
channelPrivate := th.CreatePrivateChannel(th.Context, th.BasicTeam)
th.AddUserToChannel(th.BasicUser, channelPublic)
th.AddUserToChannel(th.BasicUser, channelPrivate)
th.AddUserToChannel(th.BasicUser2, channelPublic)
// create two threads: one in public channel, one in private with only basicUser1
rootPostPublicChannel, appErr := th.App.CreatePost(th.Context, &model.Post{
UserId: th.BasicUser.Id,
ChannelId: channelPublic.Id,
Message: "root post",
}, 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: fmt.Sprintf("@%s", th.BasicUser2.Username),
}, 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",
}, 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: fmt.Sprintf("@%s", th.BasicUser2.Username),
}, 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: fmt.Sprintf("@%s", th.BasicUser2.Username),
}, channelPrivate, false, true)
require.Nil(t, appErr)
// get top threads for team, as user 1 and user 2
// user 1 should see both threads, while user 2 should see only thread in public channel.
topTeamThreadsByUser1, appErr := th.App.GetTopThreadsForTeamSince(th.Context, th.BasicTeam.Id, th.BasicUser.Id, &model.InsightsOpts{StartUnixMilli: 200, PerPage: 100})
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)
topTeamThreadsByUser2, appErr := th.App.GetTopThreadsForTeamSince(th.Context, th.BasicTeam.Id, th.BasicUser2.Id, &model.InsightsOpts{StartUnixMilli: 200, PerPage: 100})
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, appErr := th.App.GetTopThreadsForTeamSince(th.Context, th.BasicTeam.Id, th.BasicUser2.Id, &model.InsightsOpts{StartUnixMilli: 200, PerPage: 100})
require.Nil(t, appErr)
require.Len(t, topTeamThreadsByUser2IncludingPrivate.Items, 2)
}
func TestGetTopThreadsForUserSince(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
th.ConfigStore.SetReadOnlyFF(false)
defer th.ConfigStore.SetReadOnlyFF(true)
th.App.UpdateConfig(func(cfg *model.Config) { cfg.FeatureFlags.InsightsEnabled = true })
// create a public channel, a private channel
channelPublic := th.CreateChannel(th.Context, th.BasicTeam)
channelPrivate := th.CreatePrivateChannel(th.Context, th.BasicTeam)
th.AddUserToChannel(th.BasicUser, channelPublic)
th.AddUserToChannel(th.BasicUser, channelPrivate)
th.AddUserToChannel(th.BasicUser2, channelPublic)
th.AddUserToChannel(th.BasicUser2, 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 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, appErr := th.App.GetTopThreadsForUserSince(th.Context, th.BasicTeam.Id, th.BasicUser.Id, &model.InsightsOpts{StartUnixMilli: 200, PerPage: 100})
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].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].ReplyCount, int64(1))
topUser2Threads, appErr := th.App.GetTopThreadsForUserSince(th.Context, th.BasicTeam.Id, th.BasicUser2.Id, &model.InsightsOpts{StartUnixMilli: 200, PerPage: 100})
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].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)
topUser1ThreadsAfterPost1Delete, appErr := th.App.GetTopThreadsForUserSince(th.Context, th.BasicTeam.Id, th.BasicUser.Id, &model.InsightsOpts{StartUnixMilli: 200, PerPage: 100})
require.Nil(t, appErr)
require.Len(t, topUser1ThreadsAfterPost1Delete.Items, 1)
// 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, appErr := th.App.GetTopThreadsForUserSince(th.Context, th.BasicTeam.Id, th.BasicUser2.Id, &model.InsightsOpts{StartUnixMilli: 200, PerPage: 100})
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, appErr := th.App.GetTopThreadsForUserSince(th.Context, th.BasicTeam.Id, th.BasicUser2.Id, &model.InsightsOpts{StartUnixMilli: 200, PerPage: 100})
require.Nil(t, appErr)
require.Len(t, topUser2ThreadsAfterPrivateReplyDelete.Items, 0)
}
func TestGetEditHistoryForPost(t *testing.T) {
t.Skip("This needs fixing, OriginalId seems to be empty for all posts")
th := Setup(t).InitBasic()
@@ -3262,120 +3073,3 @@ func TestGetEditHistoryForPost(t *testing.T) {
require.Empty(t, edits)
})
}
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(cfg *model.Config) { cfg.FeatureFlags.InsightsEnabled = true })
// users
user := th.CreateUser()
u1 := th.CreateUser()
u2 := th.CreateUser()
u3 := th.CreateUser()
u4 := th.CreateUser()
// user direct messages
chUser1, nErr := th.App.createDirectChannel(th.Context, u1.Id, user.Id)
fmt.Println(chUser1, nErr)
require.Nil(t, nErr)
chUser2, nErr := th.App.createDirectChannel(th.Context, u2.Id, user.Id)
require.Nil(t, nErr)
chUser3, nErr := th.App.createDirectChannel(th.Context, u3.Id, user.Id)
require.Nil(t, nErr)
// other user direct message
chUser3User4, nErr := th.App.createDirectChannel(th.Context, u3.Id, u4.Id)
require.Nil(t, nErr)
// sample post data
// for u1
_, err := th.App.CreatePostAsUser(th.Context, &model.Post{
ChannelId: chUser1.Id,
UserId: u1.Id,
}, "", false)
require.Nil(t, err)
_, err = th.App.CreatePostAsUser(th.Context, &model.Post{
ChannelId: chUser1.Id,
UserId: user.Id,
}, "", false)
require.Nil(t, err)
// for u2: 1 post
_, err = th.App.CreatePostAsUser(th.Context, &model.Post{
ChannelId: chUser2.Id,
UserId: u2.Id,
}, "", false)
require.Nil(t, err)
// for user-u3: 3 posts
for i := 0; i < 3; i++ {
_, err = th.App.CreatePostAsUser(th.Context, &model.Post{
ChannelId: chUser3.Id,
UserId: user.Id,
}, "", false)
require.Nil(t, err)
}
// for u4-u3: 4 posts
_, err = th.App.CreatePostAsUser(th.Context, &model.Post{
ChannelId: chUser3User4.Id,
UserId: u3.Id,
}, "", false)
require.Nil(t, err)
_, err = th.App.CreatePostAsUser(th.Context, &model.Post{
ChannelId: chUser3User4.Id,
UserId: u4.Id,
}, "", false)
require.Nil(t, err)
_, err = th.App.CreatePostAsUser(th.Context, &model.Post{
ChannelId: chUser3User4.Id,
UserId: u3.Id,
}, "", false)
require.Nil(t, err)
_, err = th.App.CreatePostAsUser(th.Context, &model.Post{
ChannelId: chUser3User4.Id,
UserId: u4.Id,
}, "", false)
require.Nil(t, err)
t.Run("should return topDMs when userid is specified ", func(t *testing.T) {
topDMs, err := th.App.GetTopDMsForUserSince(user.Id, &model.InsightsOpts{StartUnixMilli: 100, Page: 0, PerPage: 100})
require.Nil(t, err)
// len of topDMs.Items should be 3
require.Len(t, topDMs.Items, 3)
// check order, magnitude of items
// fmt.Println(topDMs.Items[0].MessageCount, topDMs.Items[1].MessageCount, topDMs.Items[2].MessageCount)
require.Equal(t, topDMs.Items[0].SecondParticipant.Id, u3.Id)
require.Equal(t, topDMs.Items[0].MessageCount, int64(3))
require.Equal(t, topDMs.Items[1].SecondParticipant.Id, u1.Id)
require.Equal(t, topDMs.Items[1].MessageCount, int64(2))
require.Equal(t, topDMs.Items[2].SecondParticipant.Id, u2.Id)
require.Equal(t, topDMs.Items[2].MessageCount, int64(1))
// this also ensures that u3-u4 conversation doesn't show up in others' top DMs.
})
t.Run("topDMs should only consider user's DM channels ", func(t *testing.T) {
// u4 only takes part in one conversation
topDMs, err := th.App.GetTopDMsForUserSince(u4.Id, &model.InsightsOpts{StartUnixMilli: 100, Page: 0, PerPage: 100})
require.Nil(t, err)
// len of topDMs.Items should be 3
require.Len(t, topDMs.Items, 1)
// check order, magnitude of items
require.Equal(t, topDMs.Items[0].SecondParticipant.Id, u3.Id)
require.Equal(t, topDMs.Items[0].MessageCount, int64(4))
})
t.Run("topDMs will not consider deleted second user", func(t *testing.T) {
// u4 only takes part in one conversation
topDMs, err := th.App.GetTopDMsForUserSince(u4.Id, &model.InsightsOpts{StartUnixMilli: 100, Page: 0, PerPage: 100})
require.Nil(t, err)
// len of topDMs.Items should be 1
require.Len(t, topDMs.Items, 1)
// delete user3
err = th.App.PermanentDeleteUser(th.Context, u3)
require.Nil(t, err)
topDMs, err = th.App.GetTopDMsForUserSince(u4.Id, &model.InsightsOpts{StartUnixMilli: 100, Page: 0, PerPage: 100})
require.Nil(t, err)
// len of topDMs.Items should be 0 since u3 is deleted
require.Len(t, topDMs.Items, 0)
})
}

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

@@ -100,30 +100,6 @@ func populateEmptyReactions(postIDs []string, reactions map[string][]*model.Reac
return reactions
}
func (a *App) GetTopReactionsForTeamSince(teamID string, userID string, opts *model.InsightsOpts) (*model.TopReactionList, *model.AppError) {
if !a.Config().FeatureFlags.InsightsEnabled {
return nil, model.NewAppError("GetTopReactionsForTeamSince", "api.insights.feature_disabled", nil, "", http.StatusNotImplemented)
}
topReactionList, err := a.Srv().Store().Reaction().GetTopForTeamSince(teamID, userID, opts.StartUnixMilli, opts.Page*opts.PerPage, opts.PerPage)
if err != nil {
return nil, model.NewAppError("GetTopReactionsForTeamSince", model.NoTranslation, nil, "", http.StatusInternalServerError).Wrap(err)
}
return topReactionList, nil
}
func (a *App) GetTopReactionsForUserSince(userID string, teamID string, opts *model.InsightsOpts) (*model.TopReactionList, *model.AppError) {
if !a.Config().FeatureFlags.InsightsEnabled {
return nil, model.NewAppError("GetTopReactionsForUserSince", "api.insights.feature_disabled", nil, "", http.StatusNotImplemented)
}
topReactionList, err := a.Srv().Store().Reaction().GetTopForUserSince(userID, teamID, opts.StartUnixMilli, opts.Page*opts.PerPage, opts.PerPage)
if err != nil {
return nil, model.NewAppError("GetTopReactionsForUserSince", model.NoTranslation, nil, "", http.StatusInternalServerError).Wrap(err)
}
return topReactionList, nil
}
func (a *App) DeleteReactionForPost(c *request.Context, reaction *model.Reaction) *model.AppError {
post, err := a.GetSinglePost(reaction.PostId, false)
if err != nil {

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

@@ -5,7 +5,6 @@ package app
import (
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -85,347 +84,3 @@ func TestSharedChannelSyncForReactionActions(t *testing.T) {
assert.Equal(t, channel.Id, sharedChannelService.channelNotifications[1])
})
}
func TestGetTopReactionsForTeamSince(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
th.Server.platform.SetConfigReadOnlyFF(false)
defer th.Server.platform.SetConfigReadOnlyFF(true)
th.App.UpdateConfig(func(cfg *model.Config) { cfg.FeatureFlags.InsightsEnabled = true })
userId := th.BasicUser.Id
user2Id := th.BasicUser2.Id
post1 := th.CreatePost(th.BasicChannel)
post2 := th.CreatePost(th.BasicChannel)
post3 := th.CreatePost(th.BasicChannel)
post4 := th.CreatePost(th.BasicChannel)
post5 := th.CreatePost(th.BasicChannel)
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)}
timeRange, _ := model.GetStartOfDayForTimeRange(model.TimeRangeToday, time.Now().Location())
t.Run("get-top-reactions-for-team-since", func(t *testing.T) {
topReactions, err := th.App.GetTopReactionsForTeamSince(teamId, userId, &model.InsightsOpts{StartUnixMilli: timeRange.UnixMilli(), Page: 0, PerPage: 5})
require.Nil(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 = th.App.GetTopReactionsForTeamSince(teamId, userId, &model.InsightsOpts{StartUnixMilli: timeRange.UnixMilli(), Page: 1, PerPage: 5})
require.Nil(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 feature flag", func(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) { cfg.FeatureFlags.InsightsEnabled = false })
defer th.App.UpdateConfig(func(cfg *model.Config) { cfg.FeatureFlags.InsightsEnabled = true })
_, err := th.App.GetTopReactionsForTeamSince(userId, teamId, &model.InsightsOpts{StartUnixMilli: timeRange.UnixMilli(), Page: 0, PerPage: 5})
assert.NotNil(t, err)
})
}
func TestGetTopReactionsForUserSince(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
th.Server.platform.SetConfigReadOnlyFF(false)
defer th.Server.platform.SetConfigReadOnlyFF(true)
th.App.UpdateConfig(func(cfg *model.Config) { cfg.FeatureFlags.InsightsEnabled = true })
userId := th.BasicUser.Id
post1 := th.CreatePost(th.BasicChannel)
post2 := th.CreatePost(th.BasicChannel)
post3 := th.CreatePost(th.BasicChannel)
post4 := th.CreatePost(th.BasicChannel)
post5 := th.CreatePost(th.BasicChannel)
post6 := th.CreatePost(th.BasicChannel)
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)}
timeRange, _ := model.GetStartOfDayForTimeRange(model.TimeRangeToday, time.Now().Location())
t.Run("get-top-reactions-for-user-since", func(t *testing.T) {
topReactions, err := th.App.GetTopReactionsForUserSince(userId, teamId, &model.InsightsOpts{StartUnixMilli: timeRange.UnixMilli(), Page: 0, PerPage: 5})
require.Nil(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 = th.App.GetTopReactionsForUserSince(userId, teamId, &model.InsightsOpts{StartUnixMilli: timeRange.UnixMilli(), Page: 1, PerPage: 5})
require.Nil(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 feature flag", func(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) { cfg.FeatureFlags.InsightsEnabled = false })
defer th.App.UpdateConfig(func(cfg *model.Config) { cfg.FeatureFlags.InsightsEnabled = true })
_, err := th.App.GetTopReactionsForUserSince(userId, teamId, &model.InsightsOpts{StartUnixMilli: timeRange.UnixMilli(), Page: 0, PerPage: 5})
assert.NotNil(t, err)
})
}

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

@@ -2116,17 +2116,3 @@ func (a *App) ClearTeamMembersCache(teamID string) error {
}
return nil
}
func (a *App) GetNewTeamMembersSince(c request.CTX, teamID string, opts *model.InsightsOpts) (*model.NewTeamMembersList, int64, *model.AppError) {
if !a.Config().FeatureFlags.InsightsEnabled {
return nil, 0, model.NewAppError("GetNewTeamMembersSince", "app.insights.feature_disabled", nil, "", http.StatusNotImplemented)
}
showFullName := *a.Config().PrivacySettings.ShowFullName || a.SessionHasPermissionTo(*c.Session(), model.PermissionManageSystem)
ntms, count, err := a.Srv().Store().Team().GetNewTeamMembersSince(teamID, opts.StartUnixMilli, opts.Page*opts.PerPage, opts.PerPage, showFullName)
if err != nil {
return nil, 0, model.NewAppError("GetNewTeamMembersSince", model.NoTranslation, nil, "", http.StatusInternalServerError).Wrap(err)
}
return ntms, count, nil
}

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

@@ -1620,200 +1620,6 @@ func TestInviteGuestsToChannelsGracefully(t *testing.T) {
})
}
func TestGetNewTeamMembersSince(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
th.ConfigStore.SetReadOnlyFF(false)
defer th.ConfigStore.SetReadOnlyFF(true)
th.App.UpdateConfig(func(cfg *model.Config) { cfg.FeatureFlags.InsightsEnabled = true })
team := th.CreateTeam()
t.Run("counts team members", func(t *testing.T) {
var originalExpectedCount int64
var newTeamMemberJoinTime int64
var anotherUser *model.User
t.Run("since time 0", func(t *testing.T) {
teamMembers, err := th.App.Srv().Store().Team().GetMembers(team.Id, 0, 1000, nil)
require.NoError(t, err)
originalExpectedCount = int64(len(teamMembers))
_, actualCount, appErr := th.App.GetNewTeamMembersSince(th.Context, team.Id, &model.InsightsOpts{StartUnixMilli: 0, Page: 0, PerPage: 1000})
require.Nil(t, appErr)
require.Equal(t, originalExpectedCount, actualCount)
})
t.Run("after a new team member was added", func(t *testing.T) {
anotherUser = th.CreateUser()
newTeamMember, appErr := th.App.JoinUserToTeam(th.Context, team, anotherUser, "")
newTeamMemberJoinTime = newTeamMember.CreateAt
require.Nil(t, appErr)
_, actualCount, appErr := th.App.GetNewTeamMembersSince(th.Context, team.Id, &model.InsightsOpts{StartUnixMilli: 0, Page: 0, PerPage: 1000})
require.Nil(t, appErr)
require.Equal(t, originalExpectedCount+1, actualCount)
})
t.Run("after a team member was added to a different team, ensuring the wrong team's member count isn't incremented", func(t *testing.T) {
anotherUser2 := th.CreateUser()
anotherTeam := th.CreateTeam()
_, appErr := th.App.JoinUserToTeam(th.Context, anotherTeam, anotherUser2, "")
require.Nil(t, appErr)
_, actualCount, appErr := th.App.GetNewTeamMembersSince(th.Context, team.Id, &model.InsightsOpts{StartUnixMilli: 0, Page: 0, PerPage: 1000})
require.Nil(t, appErr)
require.Equal(t, originalExpectedCount+1, actualCount)
})
t.Run("since a given time", func(t *testing.T) {
_, actualCount, appErr := th.App.GetNewTeamMembersSince(th.Context, team.Id, &model.InsightsOpts{StartUnixMilli: newTeamMemberJoinTime, Page: 0, PerPage: 1000})
require.Nil(t, appErr)
require.Equal(t, int64(1), actualCount)
})
t.Run("after a team member was removed", func(t *testing.T) {
th.RemoveUserFromTeam(anotherUser, team)
_, actualCount, appErr := th.App.GetNewTeamMembersSince(th.Context, team.Id, &model.InsightsOpts{StartUnixMilli: 0, Page: 0, PerPage: 1000})
require.Nil(t, appErr)
require.Equal(t, originalExpectedCount, actualCount)
})
t.Run("after a user was deactivated", func(t *testing.T) {
_, appErr := th.App.JoinUserToTeam(th.Context, team, anotherUser, "")
require.Nil(t, appErr)
_, beforeCount, appErr := th.App.GetNewTeamMembersSince(th.Context, team.Id, &model.InsightsOpts{StartUnixMilli: 0, Page: 0, PerPage: 1000})
require.Nil(t, appErr)
_, appErr = th.App.UpdateActive(th.Context, anotherUser, false)
defer th.App.UpdateActive(th.Context, anotherUser, true)
require.Nil(t, appErr)
_, afterCount, appErr := th.App.GetNewTeamMembersSince(th.Context, team.Id, &model.InsightsOpts{StartUnixMilli: 0, Page: 0, PerPage: 1000})
require.Nil(t, appErr)
require.Equal(t, beforeCount-1, afterCount)
})
t.Run("after a user was permanently deleted", func(t *testing.T) {
_, beforeCount, appErr := th.App.GetNewTeamMembersSince(th.Context, team.Id, &model.InsightsOpts{StartUnixMilli: 0, Page: 0, PerPage: 1000})
require.Nil(t, appErr)
appErr = th.App.PermanentDeleteUser(th.Context, anotherUser)
require.Nil(t, appErr)
_, afterCount, appErr := th.App.GetNewTeamMembersSince(th.Context, team.Id, &model.InsightsOpts{StartUnixMilli: 0, Page: 0, PerPage: 1000})
require.Nil(t, appErr)
require.Equal(t, beforeCount-1, afterCount)
})
t.Run("exclude bots", func(t *testing.T) {
user := th.CreateUser()
_, appErr := th.App.ConvertUserToBot(user)
require.Nil(t, appErr)
_, appErr = th.App.JoinUserToTeam(th.Context, team, user, "")
require.Nil(t, appErr)
_, actualCount, appErr := th.App.GetNewTeamMembersSince(th.Context, team.Id, &model.InsightsOpts{StartUnixMilli: 0, Page: 0, PerPage: 1000})
require.Nil(t, appErr)
require.Equal(t, originalExpectedCount, actualCount)
})
})
t.Run("returns the correct team members", func(t *testing.T) {
var originalExpectedMembers []*model.TeamMember
var newTeamMemberJoinTime int64
var anotherUser *model.User
uIDs := func(members []*model.TeamMember) []string {
ids := []string{}
for _, member := range members {
ids = append(ids, member.UserId)
}
return ids
}
nUIDs := func(members []*model.NewTeamMember) []string {
ids := []string{}
for _, member := range members {
ids = append(ids, member.Id)
}
return ids
}
t.Run("since time 0", func(t *testing.T) {
var err error
originalExpectedMembers, err = th.App.Srv().Store().Team().GetMembers(th.BasicTeam.Id, 0, 1000, nil)
require.NoError(t, err)
actualMembersList, _, appErr := th.App.GetNewTeamMembersSince(th.Context, th.BasicTeam.Id, &model.InsightsOpts{StartUnixMilli: 0, Page: 0, PerPage: 1000})
require.Nil(t, appErr)
require.ElementsMatch(t, uIDs(originalExpectedMembers), nUIDs(actualMembersList.Items))
})
t.Run("after a new team member was added", func(t *testing.T) {
anotherUser = th.CreateUser()
newTeamMember, appErr := th.App.JoinUserToTeam(th.Context, th.BasicTeam, anotherUser, "")
newTeamMemberJoinTime = newTeamMember.CreateAt
require.Nil(t, appErr)
actualMembersList, _, appErr := th.App.GetNewTeamMembersSince(th.Context, th.BasicTeam.Id, &model.InsightsOpts{StartUnixMilli: 0, Page: 0, PerPage: 1000})
require.Nil(t, appErr)
require.ElementsMatch(t, append(uIDs(originalExpectedMembers), anotherUser.Id), nUIDs(actualMembersList.Items))
})
t.Run("after a team member was added to a different team, ensuring the wrong team's member count isn't incremented", func(t *testing.T) {
anotherUser2 := th.CreateUser()
anotherTeam := th.CreateTeam()
_, appErr := th.App.JoinUserToTeam(th.Context, anotherTeam, anotherUser2, "")
require.Nil(t, appErr)
actualMembersList, _, appErr := th.App.GetNewTeamMembersSince(th.Context, th.BasicTeam.Id, &model.InsightsOpts{StartUnixMilli: 0, Page: 0, PerPage: 1000})
require.Nil(t, appErr)
require.ElementsMatch(t, append(uIDs(originalExpectedMembers), anotherUser.Id), nUIDs(actualMembersList.Items))
})
t.Run("since a given time", func(t *testing.T) {
actualMembersList, _, appErr := th.App.GetNewTeamMembersSince(th.Context, th.BasicTeam.Id, &model.InsightsOpts{StartUnixMilli: newTeamMemberJoinTime, Page: 0, PerPage: 1000})
require.Nil(t, appErr)
require.Len(t, actualMembersList.Items, 1)
require.Equal(t, anotherUser.Id, actualMembersList.Items[0].Id)
})
t.Run("after a team member was removed", func(t *testing.T) {
th.RemoveUserFromTeam(anotherUser, th.BasicTeam)
actualMembersList, _, appErr := th.App.GetNewTeamMembersSince(th.Context, th.BasicTeam.Id, &model.InsightsOpts{StartUnixMilli: 0, Page: 0, PerPage: 1000})
require.Nil(t, appErr)
require.ElementsMatch(t, uIDs(originalExpectedMembers), nUIDs(actualMembersList.Items))
})
t.Run("after a user was deactivated", func(t *testing.T) {
_, appErr := th.App.JoinUserToTeam(th.Context, th.BasicTeam, anotherUser, "")
require.Nil(t, appErr)
beforeMembersList, _, appErr := th.App.GetNewTeamMembersSince(th.Context, th.BasicTeam.Id, &model.InsightsOpts{StartUnixMilli: 0, Page: 0, PerPage: 1000})
require.Nil(t, appErr)
require.Contains(t, nUIDs(beforeMembersList.Items), anotherUser.Id)
_, appErr = th.App.UpdateActive(th.Context, anotherUser, false)
defer th.App.UpdateActive(th.Context, anotherUser, true)
require.Nil(t, appErr)
afterMembersList, _, appErr := th.App.GetNewTeamMembersSince(th.Context, th.BasicTeam.Id, &model.InsightsOpts{StartUnixMilli: 0, Page: 0, PerPage: 1000})
require.Nil(t, appErr)
require.NotContains(t, nUIDs(afterMembersList.Items), anotherUser.Id)
})
t.Run("after a user was permanently deleted", func(t *testing.T) {
beforeMembersList, _, appErr := th.App.GetNewTeamMembersSince(th.Context, th.BasicTeam.Id, &model.InsightsOpts{StartUnixMilli: 0, Page: 0, PerPage: 1000})
require.Nil(t, appErr)
require.Contains(t, nUIDs(beforeMembersList.Items), anotherUser.Id)
appErr = th.App.PermanentDeleteUser(th.Context, anotherUser)
require.Nil(t, appErr)
afterMembersList, _, appErr := th.App.GetNewTeamMembersSince(th.Context, th.BasicTeam.Id, &model.InsightsOpts{StartUnixMilli: 0, Page: 0, PerPage: 1000})
require.Nil(t, appErr)
require.NotContains(t, nUIDs(afterMembersList.Items), anotherUser.Id)
})
t.Run("exclude bots", func(t *testing.T) {
user := th.CreateUser()
_, appErr := th.App.ConvertUserToBot(user)
require.Nil(t, appErr)
_, appErr = th.App.JoinUserToTeam(th.Context, th.BasicTeam, user, "")
require.Nil(t, appErr)
actualMembersList, _, appErr := th.App.GetNewTeamMembersSince(th.Context, th.BasicTeam.Id, &model.InsightsOpts{StartUnixMilli: 0, Page: 0, PerPage: 1000})
require.Nil(t, appErr)
require.ElementsMatch(t, uIDs(originalExpectedMembers), nUIDs(actualMembersList.Items))
})
})
}
func TestTeamSendEvents(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()

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

@@ -284,14 +284,6 @@ func (a *App) createUserOrGuest(c request.CTX, user *model.User, guest bool) (*m
tutorialStepPref := model.Preference{UserId: ruser.Id, Category: model.PreferenceCategoryTutorialSteps, Name: ruser.Id, Value: "0"}
preferences := model.Preferences{recommendedNextStepsPref, tutorialStepPref}
if a.Config().FeatureFlags.InsightsEnabled {
// We don't want to show the insights intro modal for new users
preferences = append(preferences, model.Preference{UserId: ruser.Id, Category: model.PreferenceCategoryInsights, Name: model.PreferenceNameInsights, Value: "{\"insights_modal_viewed\":true}"})
} else {
preferences = append(preferences, model.Preference{UserId: ruser.Id, Category: model.PreferenceCategoryInsights, Name: model.PreferenceNameInsights, Value: "{\"insights_modal_viewed\":false}"})
}
if err := a.Srv().Store().Preference().Save(preferences); err != nil {
c.Logger().Warn("Encountered error saving user preferences", mlog.Err(err))
}

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

@@ -1810,16 +1810,10 @@ func TestCreateUserWithInitialPreferences(t *testing.T) {
t.Run("successfully create a user with initial tutorial and recommended steps preferences", func(t *testing.T) {
th.ConfigStore.SetReadOnlyFF(false)
defer th.ConfigStore.SetReadOnlyFF(true)
th.App.UpdateConfig(func(cfg *model.Config) { cfg.FeatureFlags.InsightsEnabled = true })
testUser := th.CreateUser()
defer th.App.PermanentDeleteUser(th.Context, testUser)
insightsPref, appErr := th.App.GetPreferenceByCategoryAndNameForUser(testUser.Id, model.PreferenceCategoryInsights, model.PreferenceNameInsights)
require.Nil(t, appErr)
assert.Equal(t, "insights_tutorial_state", insightsPref.Name)
assert.Equal(t, "{\"insights_modal_viewed\":true}", insightsPref.Value)
tutorialStepPref, appErr := th.App.GetPreferenceByCategoryAndNameForUser(testUser.Id, model.PreferenceCategoryTutorialSteps, testUser.Id)
require.Nil(t, appErr)
assert.Equal(t, testUser.Id, tutorialStepPref.Name)
@@ -1831,38 +1825,12 @@ func TestCreateUserWithInitialPreferences(t *testing.T) {
assert.Equal(t, "false", recommendedNextStepsPref[0].Value)
})
t.Run("successfully create a user with insights feature flag disabled", func(t *testing.T) {
t.Run("successfully create a guest user with initial tutorial and recommended steps preferences", func(t *testing.T) {
th.Server.platform.SetConfigReadOnlyFF(false)
defer th.Server.platform.SetConfigReadOnlyFF(true)
th.App.UpdateConfig(func(cfg *model.Config) { cfg.FeatureFlags.InsightsEnabled = false })
defer th.App.UpdateConfig(func(cfg *model.Config) { cfg.FeatureFlags.InsightsEnabled = true })
testUser := th.CreateUser()
defer th.App.PermanentDeleteUser(th.Context, testUser)
insightsPref, appErr := th.App.GetPreferenceByCategoryAndNameForUser(testUser.Id, model.PreferenceCategoryInsights, model.PreferenceNameInsights)
require.Nil(t, appErr)
assert.Equal(t, "insights_tutorial_state", insightsPref.Name)
assert.Equal(t, "{\"insights_modal_viewed\":false}", insightsPref.Value)
recommendedNextStepsPref, appErr := th.App.GetPreferenceByCategoryForUser(testUser.Id, model.PreferenceRecommendedNextSteps)
require.Nil(t, appErr)
assert.Equal(t, model.PreferenceRecommendedNextSteps, recommendedNextStepsPref[0].Category)
assert.Equal(t, "hide", recommendedNextStepsPref[0].Name)
assert.Equal(t, "false", recommendedNextStepsPref[0].Value)
})
t.Run("successfully create a guest user with initial tutorial, insights and recommended steps preferences", func(t *testing.T) {
th.Server.platform.SetConfigReadOnlyFF(false)
defer th.Server.platform.SetConfigReadOnlyFF(true)
th.App.UpdateConfig(func(cfg *model.Config) { cfg.FeatureFlags.InsightsEnabled = true })
testUser := th.CreateGuest()
defer th.App.PermanentDeleteUser(th.Context, testUser)
insightsPref, appErr := th.App.GetPreferenceByCategoryAndNameForUser(testUser.Id, model.PreferenceCategoryInsights, model.PreferenceNameInsights)
require.Nil(t, appErr)
assert.Equal(t, "insights_tutorial_state", insightsPref.Name)
assert.Equal(t, "{\"insights_modal_viewed\":true}", insightsPref.Value)
tutorialStepPref, appErr := th.App.GetPreferenceByCategoryAndNameForUser(testUser.Id, model.PreferenceCategoryTutorialSteps, testUser.Id)
require.Nil(t, appErr)
assert.Equal(t, testUser.Id, tutorialStepPref.Name)