[MM-42742] Add top reactions endpoint (#19850)
Этот коммит содержится в:
@@ -6496,6 +6496,39 @@ func (c *Client4) GetBulkReactions(postIds []string) (map[string][]*Reaction, *R
|
||||
return reactions, BuildResponse(r), nil
|
||||
}
|
||||
|
||||
func (c *Client4) GetTopReactionsForTeamSince(teamId string, timeRange string, page int, perPage int) (*TopReactionList, *Response, error) {
|
||||
query := fmt.Sprintf("?time_range=%v&page=%v&per_page=%v", timeRange, page, perPage)
|
||||
r, err := c.DoAPIGet(c.teamRoute(teamId)+"/top/reactions"+query, "")
|
||||
if err != nil {
|
||||
return nil, BuildResponse(r), err
|
||||
}
|
||||
defer closeBody(r)
|
||||
var topReactions *TopReactionList
|
||||
if jsonErr := json.NewDecoder(r.Body).Decode(&topReactions); jsonErr != nil {
|
||||
return nil, nil, NewAppError("GetTopReactionsForTeamSince", "api.unmarshal_error", nil, jsonErr.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
return topReactions, BuildResponse(r), nil
|
||||
}
|
||||
|
||||
func (c *Client4) GetTopReactionsForUserSince(teamId string, timeRange string, page int, perPage int) (*TopReactionList, *Response, error) {
|
||||
query := fmt.Sprintf("?time_range=%v&page=%v&per_page=%v", timeRange, page, perPage)
|
||||
|
||||
if teamId != "" {
|
||||
query += fmt.Sprintf("&team_id=%v", teamId)
|
||||
}
|
||||
|
||||
r, err := c.DoAPIGet(c.usersRoute()+"/me/top/reactions"+query, "")
|
||||
if err != nil {
|
||||
return nil, BuildResponse(r), err
|
||||
}
|
||||
defer closeBody(r)
|
||||
var topReactions *TopReactionList
|
||||
if jsonErr := json.NewDecoder(r.Body).Decode(&topReactions); jsonErr != nil {
|
||||
return nil, nil, NewAppError("GetTopReactionsForUserSince", "api.unmarshal_error", nil, jsonErr.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
return topReactions, BuildResponse(r), nil
|
||||
}
|
||||
|
||||
// Timezone Section
|
||||
|
||||
// GetSupportedTimezone returns a page of supported timezones on the system.
|
||||
|
||||
76
model/insights.go
Обычный файл
76
model/insights.go
Обычный файл
@@ -0,0 +1,76 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
TimeRangeToday string = "today"
|
||||
TimeRange7Day string = "7_day"
|
||||
TimeRange28Day string = "28_day"
|
||||
)
|
||||
|
||||
type InsightsOpts struct {
|
||||
StartUnixMilli int64
|
||||
Page int
|
||||
PerPage int
|
||||
}
|
||||
|
||||
type InsightsListData struct {
|
||||
HasNext bool `json:"has_next"`
|
||||
}
|
||||
|
||||
type InsightsData struct {
|
||||
Rank int `json:"rank"`
|
||||
}
|
||||
|
||||
type TopReactionList struct {
|
||||
InsightsListData
|
||||
Items []*TopReaction `json:"items"`
|
||||
}
|
||||
|
||||
type TopReaction struct {
|
||||
InsightsData
|
||||
EmojiName string `json:"emoji_name"`
|
||||
Count int64 `json:"count"`
|
||||
}
|
||||
|
||||
// GetStartUnixMilliForTimeRange gets the unix start time in milliseconds from the given time range.
|
||||
// Time range can be one of: "1_day", "7_day", or "28_day".
|
||||
func GetStartUnixMilliForTimeRange(timeRange string) (int64, *AppError) {
|
||||
now := time.Now()
|
||||
_, offset := now.Zone()
|
||||
switch timeRange {
|
||||
case TimeRangeToday:
|
||||
return GetStartOfDayMillis(now, offset), nil
|
||||
case TimeRange7Day:
|
||||
return GetStartOfDayMillis(now.Add(time.Hour*time.Duration(-168)), offset), nil
|
||||
case TimeRange28Day:
|
||||
return GetStartOfDayMillis(now.Add(time.Hour*time.Duration(-672)), offset), nil
|
||||
}
|
||||
|
||||
return GetStartOfDayMillis(now, offset), NewAppError("Insights.IsValidRequest", "model.insights.time_range.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
// GetTopReactionListWithRankAndPagination adds a rank to each item in the given list of TopReaction and checks if there is
|
||||
// another page that can be fetched based on the given limit and offset. The given list of TopReaction is assumed to be
|
||||
// sorted by Count. Returns a TopReactionList.
|
||||
func GetTopReactionListWithRankAndPagination(reactions []*TopReaction, limit int, offset int) *TopReactionList {
|
||||
// Add pagination support
|
||||
var hasNext bool
|
||||
if (limit != 0) && (len(reactions) == limit+1) {
|
||||
hasNext = true
|
||||
reactions = reactions[:len(reactions)-1]
|
||||
}
|
||||
|
||||
// Assign rank to each reaction
|
||||
for i, reaction := range reactions {
|
||||
reaction.Rank = offset + i + 1
|
||||
}
|
||||
|
||||
return &TopReactionList{InsightsListData: InsightsListData{HasNext: hasNext}, Items: reactions}
|
||||
}
|
||||
81
model/insights_test.go
Обычный файл
81
model/insights_test.go
Обычный файл
@@ -0,0 +1,81 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestGetStartUnixMilliForTimeRang(t *testing.T) {
|
||||
tc := [3]string{"today", "7_day", "28_day"}
|
||||
|
||||
for _, timeRange := range tc {
|
||||
t.Run(timeRange, func(t *testing.T) {
|
||||
_, err := GetStartUnixMilliForTimeRange(timeRange)
|
||||
assert.Nil(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
invalidTimeRanges := [3]string{"", "1_day", "10_day"}
|
||||
|
||||
for _, timeRange := range invalidTimeRanges {
|
||||
t.Run(timeRange, func(t *testing.T) {
|
||||
_, err := GetStartUnixMilliForTimeRange(timeRange)
|
||||
assert.NotNil(t, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetTopReactionListWithRankAndPagination(t *testing.T) {
|
||||
|
||||
reactions := []*TopReaction{
|
||||
{EmojiName: "smile", Count: 200},
|
||||
{EmojiName: "+1", Count: 190},
|
||||
{EmojiName: "100", Count: 100},
|
||||
{EmojiName: "-1", Count: 75},
|
||||
{EmojiName: "checkmark", Count: 50},
|
||||
{EmojiName: "mattermost", Count: 49}}
|
||||
|
||||
hasNextTC := []struct {
|
||||
Description string
|
||||
Limit int
|
||||
Offset int
|
||||
Expected *TopReactionList
|
||||
}{
|
||||
{
|
||||
Description: "has one page",
|
||||
Limit: len(reactions),
|
||||
Offset: 0,
|
||||
Expected: &TopReactionList{InsightsListData: InsightsListData{HasNext: false}, Items: reactions},
|
||||
},
|
||||
{
|
||||
Description: "has more than one page",
|
||||
Limit: len(reactions) - 1,
|
||||
Offset: 0,
|
||||
Expected: &TopReactionList{InsightsListData: InsightsListData{HasNext: true}, Items: reactions},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range hasNextTC {
|
||||
t.Run(test.Description, func(t *testing.T) {
|
||||
actual := GetTopReactionListWithRankAndPagination(reactions, test.Limit, test.Offset)
|
||||
assert.Equal(t, test.Expected.HasNext, actual.HasNext)
|
||||
})
|
||||
}
|
||||
|
||||
t.Run("ranks for first and second page", func(t *testing.T) {
|
||||
firstPage := GetTopReactionListWithRankAndPagination(reactions, 5, 0)
|
||||
|
||||
for i, r := range firstPage.Items {
|
||||
assert.Equal(t, i+1, r.Rank)
|
||||
}
|
||||
|
||||
secondPage := GetTopReactionListWithRankAndPagination(reactions, 5, 5)
|
||||
for i, r := range secondPage.Items {
|
||||
assert.Equal(t, i+1+5, r.Rank)
|
||||
}
|
||||
})
|
||||
}
|
||||
Ссылка в новой задаче
Block a user