[MM-42742] Add top reactions endpoint (#19850)

Этот коммит содержится в:
Mylon Suren
2022-04-14 13:09:35 -04:00
коммит произвёл GitHub
родитель a98975b00f
Коммит 99f02fe96e
18 изменённых файлов: 1360 добавлений и 0 удалений

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

@@ -754,6 +754,8 @@ 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)
GetTopReactionsForTeamSince(teamID string, userID string, opts *model.InsightsOpts) (*model.TopReactionList, *model.AppError)
GetTopReactionsForUserSince(userID string, teamID string, opts *model.InsightsOpts) (*model.TopReactionList, *model.AppError)
GetUploadSession(uploadId string) (*model.UploadSession, *model.AppError)
GetUploadSessionsForUser(userID string) ([]*model.UploadSession, *model.AppError)
GetUser(userID string) (*model.User, *model.AppError)

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

@@ -9596,6 +9596,50 @@ func (a *OpenTracingAppLayer) GetTokenById(token string) (*model.Token, *model.A
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) GetTotalUsersStats(viewRestrictions *model.ViewUsersRestrictions) (*model.UsersStats, *model.AppError) {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetTotalUsersStats")

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

@@ -96,6 +96,30 @@ 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", "app.reaction.get_top_for_team_since.app_error", nil, err.Error(), http.StatusInternalServerError)
}
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", "app.reaction.get_top_for_user_since.app_error", nil, err.Error(), http.StatusInternalServerError)
}
return topReactionList, nil
}
func (a *App) DeleteReactionForPost(c *request.Context, reaction *model.Reaction) *model.AppError {
post, err := a.GetSinglePost(reaction.PostId)
if err != nil {

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

@@ -5,6 +5,7 @@ package app
import (
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -84,3 +85,345 @@ 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.configStore.SetReadOnlyFF(false)
defer th.Server.configStore.SetReadOnlyFF(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.GetStartUnixMilliForTimeRange(model.TimeRangeToday)
t.Run("get-top-reactions-for-team-since", func(t *testing.T) {
topReactions, err := th.App.GetTopReactionsForTeamSince(teamId, userId, &model.InsightsOpts{StartUnixMilli: timeRange, 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, 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 })
_, err := th.App.GetTopReactionsForTeamSince(userId, teamId, &model.InsightsOpts{StartUnixMilli: timeRange, Page: 0, PerPage: 5})
assert.NotNil(t, err)
})
}
func TestGetTopReactionsForUserSince(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
th.Server.configStore.SetReadOnlyFF(false)
defer th.Server.configStore.SetReadOnlyFF(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.GetStartUnixMilliForTimeRange(model.TimeRangeToday)
t.Run("get-top-reactions-for-user-since", func(t *testing.T) {
topReactions, err := th.App.GetTopReactionsForUserSince(userId, teamId, &model.InsightsOpts{StartUnixMilli: timeRange, 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, 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 })
_, err := th.App.GetTopReactionsForUserSince(userId, teamId, &model.InsightsOpts{StartUnixMilli: timeRange, Page: 0, PerPage: 5})
assert.NotNil(t, err)
})
}