MM-43956: Adds post counts by duration. (#20131)
* MM-43956: Adds post counts by day. * MM-43956: Test data cleanup. Switch from Unix to UnixMilli. * MM-43956: Changes from selecting date data types to strings in SQL. * MM-43956: Fixes date format key. * MM-43956: Adds missing user id scope for 'my' top channels graph. * MM-43956: Adds the ability to group post counts by hour. * MM-43956: Require enterprise or professional license. Reject guests. * MM-43956: Adds license for tests. * MM-43956: Renames function. * MM-43956: Omits future hours from post counts by hour. * MM-43956: Adjust API response grouping to users timezone. * MM-43956: Adds translation. * MM-43956: Adds user's timezone to the data tier for the grouping by day and hour. * MM-43956: Fixes layers. * MM-43956: Lint fix. * MM-43956: Fix store layers. * MM-43956: Switches to default name for time package; changes parameter names to avoid naming conflict. * MM-43956: Updates mocks. Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
c03eb778c8
Коммит
182ae1234a
@@ -209,3 +209,24 @@ func requireLicense(f handlerFunc) handlerFunc {
|
||||
f(c, w, r)
|
||||
}
|
||||
}
|
||||
|
||||
func minimumProfessionalLicense(f handlerFunc) handlerFunc {
|
||||
return func(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
lic := c.App.Srv().License()
|
||||
if lic == nil || (lic.SkuShortName != model.LicenseShortSkuProfessional && lic.SkuShortName != model.LicenseShortSkuEnterprise) {
|
||||
c.Err = model.NewAppError("", "api.license_error.professional_or_enterprise", nil, "", http.StatusNotImplemented)
|
||||
return
|
||||
}
|
||||
f(c, w, r)
|
||||
}
|
||||
}
|
||||
|
||||
func rejectGuests(f handlerFunc) handlerFunc {
|
||||
return func(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
if c.AppContext.Session().Props[model.SessionPropIsGuest] == "true" {
|
||||
c.Err = model.NewAppError("", "api.authorization_error.guest", nil, "", http.StatusNotImplemented)
|
||||
return
|
||||
}
|
||||
f(c, w, r)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,18 +6,20 @@ package api4
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/mattermost/mattermost-server/v6/app"
|
||||
"github.com/mattermost/mattermost-server/v6/model"
|
||||
)
|
||||
|
||||
func (api *API) InitInsights() {
|
||||
// Reactions
|
||||
api.BaseRoutes.InsightsForTeam.Handle("/reactions", api.APISessionRequired(getTopReactionsForTeamSince)).Methods("GET")
|
||||
api.BaseRoutes.InsightsForUser.Handle("/reactions", api.APISessionRequired(getTopReactionsForUserSince)).Methods("GET")
|
||||
api.BaseRoutes.InsightsForTeam.Handle("/reactions", api.APISessionRequired(minimumProfessionalLicense(rejectGuests(getTopReactionsForTeamSince)))).Methods("GET")
|
||||
api.BaseRoutes.InsightsForUser.Handle("/reactions", api.APISessionRequired(minimumProfessionalLicense(rejectGuests(getTopReactionsForUserSince)))).Methods("GET")
|
||||
|
||||
// Channels
|
||||
api.BaseRoutes.InsightsForTeam.Handle("/channels", api.APISessionRequired(getTopChannelsForTeamSince)).Methods("GET")
|
||||
api.BaseRoutes.InsightsForUser.Handle("/channels", api.APISessionRequired(getTopChannelsForUserSince)).Methods("GET")
|
||||
api.BaseRoutes.InsightsForTeam.Handle("/channels", api.APISessionRequired(minimumProfessionalLicense(rejectGuests(getTopChannelsForTeamSince)))).Methods("GET")
|
||||
api.BaseRoutes.InsightsForUser.Handle("/channels", api.APISessionRequired(minimumProfessionalLicense(rejectGuests(getTopChannelsForUserSince)))).Methods("GET")
|
||||
}
|
||||
|
||||
// Top Reactions
|
||||
@@ -39,14 +41,16 @@ func getTopReactionsForTeamSince(c *Context, w http.ResponseWriter, r *http.Requ
|
||||
return
|
||||
}
|
||||
|
||||
startTime, err := model.GetStartUnixMilliForTimeRange(c.Params.TimeRange)
|
||||
user, err := c.App.GetUser(c.AppContext.Session().UserId)
|
||||
if err != nil {
|
||||
c.Err = err
|
||||
return
|
||||
}
|
||||
|
||||
startTime := model.StartOfDayForTimeRange(c.Params.TimeRange, user.GetTimezoneLocation())
|
||||
|
||||
topReactionList, err := c.App.GetTopReactionsForTeamSince(c.Params.TeamId, c.AppContext.Session().UserId, &model.InsightsOpts{
|
||||
StartUnixMilli: startTime,
|
||||
StartUnixMilli: startTime.UnixMilli(),
|
||||
Page: c.Params.Page,
|
||||
PerPage: c.Params.PerPage,
|
||||
})
|
||||
@@ -86,14 +90,16 @@ func getTopReactionsForUserSince(c *Context, w http.ResponseWriter, r *http.Requ
|
||||
}
|
||||
}
|
||||
|
||||
startTime, err := model.GetStartUnixMilliForTimeRange(c.Params.TimeRange)
|
||||
user, err := c.App.GetUser(c.AppContext.Session().UserId)
|
||||
if err != nil {
|
||||
c.Err = err
|
||||
return
|
||||
}
|
||||
|
||||
startTime := model.StartOfDayForTimeRange(c.Params.TimeRange, user.GetTimezoneLocation())
|
||||
|
||||
topReactionList, err := c.App.GetTopReactionsForUserSince(c.AppContext.Session().UserId, c.Params.TeamId, &model.InsightsOpts{
|
||||
StartUnixMilli: startTime,
|
||||
StartUnixMilli: startTime.UnixMilli(),
|
||||
Page: c.Params.Page,
|
||||
PerPage: c.Params.PerPage,
|
||||
})
|
||||
@@ -130,14 +136,17 @@ func getTopChannelsForTeamSince(c *Context, w http.ResponseWriter, r *http.Reque
|
||||
return
|
||||
}
|
||||
|
||||
startTime, err := model.GetStartUnixMilliForTimeRange(c.Params.TimeRange)
|
||||
user, err := c.App.GetUser(c.AppContext.Session().UserId)
|
||||
if err != nil {
|
||||
c.Err = err
|
||||
return
|
||||
}
|
||||
|
||||
loc := user.GetTimezoneLocation()
|
||||
startTime := model.StartOfDayForTimeRange(c.Params.TimeRange, loc)
|
||||
|
||||
topChannels, err := c.App.GetTopChannelsForTeamSince(c.Params.TeamId, c.AppContext.Session().UserId, &model.InsightsOpts{
|
||||
StartUnixMilli: startTime,
|
||||
StartUnixMilli: startTime.UnixMilli(),
|
||||
Page: c.Params.Page,
|
||||
PerPage: c.Params.PerPage,
|
||||
})
|
||||
@@ -146,6 +155,12 @@ func getTopChannelsForTeamSince(c *Context, w http.ResponseWriter, r *http.Reque
|
||||
return
|
||||
}
|
||||
|
||||
topChannels.PostCountByDuration, err = postCountByDurationViewModel(c.App, topChannels, startTime, c.Params.TimeRange, nil, loc)
|
||||
if err != nil {
|
||||
c.Err = err
|
||||
return
|
||||
}
|
||||
|
||||
js, jsonErr := json.Marshal(topChannels)
|
||||
if jsonErr != nil {
|
||||
c.Err = model.NewAppError("getTopChannelsForTeamSince", "api.marshal_error", nil, jsonErr.Error(), http.StatusInternalServerError)
|
||||
@@ -177,14 +192,17 @@ func getTopChannelsForUserSince(c *Context, w http.ResponseWriter, r *http.Reque
|
||||
}
|
||||
}
|
||||
|
||||
startTime, err := model.GetStartUnixMilliForTimeRange(c.Params.TimeRange)
|
||||
user, err := c.App.GetUser(c.AppContext.Session().UserId)
|
||||
if err != nil {
|
||||
c.Err = err
|
||||
return
|
||||
}
|
||||
|
||||
loc := user.GetTimezoneLocation()
|
||||
startTime := model.StartOfDayForTimeRange(c.Params.TimeRange, loc)
|
||||
|
||||
topChannels, err := c.App.GetTopChannelsForUserSince(c.AppContext.Session().UserId, c.Params.TeamId, &model.InsightsOpts{
|
||||
StartUnixMilli: startTime,
|
||||
StartUnixMilli: startTime.UnixMilli(),
|
||||
Page: c.Params.Page,
|
||||
PerPage: c.Params.PerPage,
|
||||
})
|
||||
@@ -194,6 +212,12 @@ func getTopChannelsForUserSince(c *Context, w http.ResponseWriter, r *http.Reque
|
||||
return
|
||||
}
|
||||
|
||||
topChannels.PostCountByDuration, err = postCountByDurationViewModel(c.App, topChannels, startTime, c.Params.TimeRange, &c.AppContext.Session().UserId, loc)
|
||||
if err != nil {
|
||||
c.Err = err
|
||||
return
|
||||
}
|
||||
|
||||
js, jsonErr := json.Marshal(topChannels)
|
||||
if jsonErr != nil {
|
||||
c.Err = model.NewAppError("getTopChannelsForUserSince", "api.marshal_error", nil, jsonErr.Error(), http.StatusInternalServerError)
|
||||
@@ -202,3 +226,23 @@ func getTopChannelsForUserSince(c *Context, w http.ResponseWriter, r *http.Reque
|
||||
|
||||
w.Write(js)
|
||||
}
|
||||
|
||||
// postCountByDurationViewModel expects a list of channels that are pre-authorized for the given user to view.
|
||||
func postCountByDurationViewModel(app app.AppIface, topChannelList *model.TopChannelList, startTime *time.Time, timeRange string, userID *string, location *time.Location) (model.ChannelPostCountByDuration, *model.AppError) {
|
||||
if len(topChannelList.Items) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
var postCountsByDay []*model.DurationPostCount
|
||||
channelIDs := topChannelList.ChannelIDs()
|
||||
var grouping model.PostCountGrouping
|
||||
if timeRange == model.TimeRangeToday {
|
||||
grouping = model.PostsByHour
|
||||
} else {
|
||||
grouping = model.PostsByDay
|
||||
}
|
||||
postCountsByDay, err := app.PostCountsByDuration(channelIDs, startTime.UnixMilli(), userID, grouping, location)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return model.ToDailyPostCountViewModel(postCountsByDay, startTime, model.TimeRangeToNumberDays(timeRange), channelIDs), nil
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ func TestGetTopReactionsForTeamSince(t *testing.T) {
|
||||
th.ConfigStore.SetReadOnlyFF(false)
|
||||
defer th.ConfigStore.SetReadOnlyFF(true)
|
||||
th.App.UpdateConfig(func(cfg *model.Config) { cfg.FeatureFlags.InsightsEnabled = true })
|
||||
th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuProfessional))
|
||||
|
||||
client := th.Client
|
||||
|
||||
@@ -246,6 +247,7 @@ func TestGetTopReactionsForUserSince(t *testing.T) {
|
||||
th.ConfigStore.SetReadOnlyFF(false)
|
||||
defer th.ConfigStore.SetReadOnlyFF(true)
|
||||
th.App.UpdateConfig(func(cfg *model.Config) { cfg.FeatureFlags.InsightsEnabled = true })
|
||||
th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuProfessional))
|
||||
|
||||
client := th.Client
|
||||
|
||||
@@ -437,6 +439,7 @@ func TestGetTopChannelsForTeamSince(t *testing.T) {
|
||||
th.ConfigStore.SetReadOnlyFF(false)
|
||||
defer th.ConfigStore.SetReadOnlyFF(true)
|
||||
th.App.UpdateConfig(func(cfg *model.Config) { cfg.FeatureFlags.InsightsEnabled = true })
|
||||
th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuProfessional))
|
||||
|
||||
client := th.Client
|
||||
userId := th.BasicUser.Id
|
||||
@@ -485,6 +488,10 @@ func TestGetTopChannelsForTeamSince(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, channel6.Id, topChannels.Items[0].ID)
|
||||
assert.Equal(t, int64(1), topChannels.Items[0].MessageCount)
|
||||
|
||||
t.Run("has post count by day", func(t *testing.T) {
|
||||
require.NotNil(t, topChannels.PostCountByDuration)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("get-top-channels-for-user-since exclude channels user is not member of", func(t *testing.T) {
|
||||
@@ -531,6 +538,7 @@ func TestGetTopChannelsForUserSince(t *testing.T) {
|
||||
th.ConfigStore.SetReadOnlyFF(false)
|
||||
defer th.ConfigStore.SetReadOnlyFF(true)
|
||||
th.App.UpdateConfig(func(cfg *model.Config) { cfg.FeatureFlags.InsightsEnabled = true })
|
||||
th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuProfessional))
|
||||
|
||||
client := th.Client
|
||||
userId := th.BasicUser.Id
|
||||
@@ -579,6 +587,10 @@ func TestGetTopChannelsForUserSince(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, channel6.Id, topChannels.Items[0].ID)
|
||||
assert.Equal(t, int64(1), topChannels.Items[0].MessageCount)
|
||||
|
||||
t.Run("has post count by day", func(t *testing.T) {
|
||||
require.NotNil(t, topChannels.PostCountByDuration)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("get-top-channels-for-user-since invalid team id", func(t *testing.T) {
|
||||
|
||||
@@ -262,6 +262,12 @@ 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 *WebConnConfig, seqVal string) (*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(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
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/mattermost/mattermost-server/v6/app/request"
|
||||
"github.com/mattermost/mattermost-server/v6/model"
|
||||
@@ -3417,3 +3418,19 @@ func (a *App) GetTopChannelsForUserSince(userID, teamID string, opts *model.Insi
|
||||
}
|
||||
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(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", "app.channel.get_post_count_by_day.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
return postCountByDay, nil
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
@@ -2418,10 +2419,10 @@ func TestGetTopChannelsForTeamSince(t *testing.T) {
|
||||
{ID: channel5.Id, MessageCount: 2},
|
||||
}
|
||||
|
||||
timeRange, _ := model.GetStartUnixMilliForTimeRange(model.TimeRangeToday)
|
||||
timeRange := model.StartOfDayForTimeRange(model.TimeRangeToday, time.Now().Location())
|
||||
|
||||
t.Run("get-top-channels-for-team-since", func(t *testing.T) {
|
||||
topChannels, err := th.App.GetTopChannelsForTeamSince(th.BasicChannel.TeamId, th.BasicUser.Id, &model.InsightsOpts{StartUnixMilli: timeRange, Page: 0, PerPage: 5})
|
||||
topChannels, err := th.App.GetTopChannelsForTeamSince(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 {
|
||||
@@ -2429,7 +2430,7 @@ func TestGetTopChannelsForTeamSince(t *testing.T) {
|
||||
assert.Equal(t, expectedTopChannels[i].MessageCount, channel.MessageCount)
|
||||
}
|
||||
|
||||
topChannels, err = th.App.GetTopChannelsForTeamSince(th.BasicChannel.TeamId, th.BasicUser.Id, &model.InsightsOpts{StartUnixMilli: timeRange, Page: 1, PerPage: 5})
|
||||
topChannels, err = th.App.GetTopChannelsForTeamSince(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)
|
||||
@@ -2476,10 +2477,10 @@ func TestGetTopChannelsForUserSince(t *testing.T) {
|
||||
{ID: channel5.Id, MessageCount: 2},
|
||||
}
|
||||
|
||||
timeRange, _ := model.GetStartUnixMilliForTimeRange(model.TimeRangeToday)
|
||||
timeRange := model.StartOfDayForTimeRange(model.TimeRangeToday, time.Now().Location())
|
||||
|
||||
t.Run("get-top-channels-for-user-since", func(t *testing.T) {
|
||||
topChannels, err := th.App.GetTopChannelsForUserSince(th.BasicUser.Id, "", &model.InsightsOpts{StartUnixMilli: timeRange, Page: 0, PerPage: 5})
|
||||
topChannels, err := th.App.GetTopChannelsForUserSince(th.BasicUser.Id, "", &model.InsightsOpts{StartUnixMilli: timeRange.UnixMilli(), Page: 0, PerPage: 5})
|
||||
require.Nil(t, err)
|
||||
|
||||
for i, channel := range topChannels.Items {
|
||||
@@ -2487,9 +2488,132 @@ func TestGetTopChannelsForUserSince(t *testing.T) {
|
||||
assert.Equal(t, expectedTopChannels[i].MessageCount, channel.MessageCount)
|
||||
}
|
||||
|
||||
topChannels, err = th.App.GetTopChannelsForUserSince(th.BasicUser.Id, th.BasicChannel.TeamId, &model.InsightsOpts{StartUnixMilli: timeRange, Page: 1, PerPage: 5})
|
||||
topChannels, err = th.App.GetTopChannelsForUserSince(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.Server.configStore.SetReadOnlyFF(false)
|
||||
defer th.Server.configStore.SetReadOnlyFF(true)
|
||||
th.App.UpdateConfig(func(cfg *model.Config) { cfg.FeatureFlags.InsightsEnabled = true })
|
||||
|
||||
channel2 := th.CreateChannel(th.BasicTeam)
|
||||
channel3 := th.CreatePrivateChannel(th.BasicTeam)
|
||||
channel4 := th.CreatePrivateChannel(th.BasicTeam)
|
||||
channel5 := th.CreateChannel(th.BasicTeam)
|
||||
channel6 := th.CreatePrivateChannel(th.BasicTeam)
|
||||
defer func() {
|
||||
th.App.PermanentDeleteChannel(channel2)
|
||||
th.App.PermanentDeleteChannel(channel3)
|
||||
th.App.PermanentDeleteChannel(channel4)
|
||||
th.App.PermanentDeleteChannel(channel5)
|
||||
th.App.PermanentDeleteChannel(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(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(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(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)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -12654,6 +12654,28 @@ func (a *OpenTracingAppLayer) PostAddToChannelMessage(c *request.Context, user *
|
||||
return resultVar0
|
||||
}
|
||||
|
||||
func (a *OpenTracingAppLayer) PostCountsByDuration(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(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")
|
||||
|
||||
@@ -231,10 +231,10 @@ func TestGetTopReactionsForTeamSince(t *testing.T) {
|
||||
expectedTopReactions[3] = &model.TopReaction{EmojiName: "sad", Count: int64(3)}
|
||||
expectedTopReactions[4] = &model.TopReaction{EmojiName: "happy", Count: int64(2)}
|
||||
|
||||
timeRange, _ := model.GetStartUnixMilliForTimeRange(model.TimeRangeToday)
|
||||
timeRange := model.StartOfDayForTimeRange(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, Page: 0, PerPage: 5})
|
||||
topReactions, err := th.App.GetTopReactionsForTeamSince(teamId, userId, &model.InsightsOpts{StartUnixMilli: timeRange.UnixMilli(), Page: 0, PerPage: 5})
|
||||
require.Nil(t, err)
|
||||
reactions := topReactions.Items
|
||||
|
||||
@@ -242,7 +242,7 @@ func TestGetTopReactionsForTeamSince(t *testing.T) {
|
||||
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})
|
||||
topReactions, err = th.App.GetTopReactionsForTeamSince(teamId, userId, &model.InsightsOpts{StartUnixMilli: timeRange.UnixMilli(), Page: 1, PerPage: 5})
|
||||
require.Nil(t, err)
|
||||
reactions = topReactions.Items
|
||||
|
||||
@@ -252,7 +252,7 @@ func TestGetTopReactionsForTeamSince(t *testing.T) {
|
||||
|
||||
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})
|
||||
_, err := th.App.GetTopReactionsForTeamSince(userId, teamId, &model.InsightsOpts{StartUnixMilli: timeRange.UnixMilli(), Page: 0, PerPage: 5})
|
||||
assert.NotNil(t, err)
|
||||
})
|
||||
}
|
||||
@@ -402,10 +402,10 @@ func TestGetTopReactionsForUserSince(t *testing.T) {
|
||||
expectedTopReactions[3] = &model.TopReaction{EmojiName: "heart", Count: int64(3)}
|
||||
expectedTopReactions[4] = &model.TopReaction{EmojiName: "blush", Count: int64(2)}
|
||||
|
||||
timeRange, _ := model.GetStartUnixMilliForTimeRange(model.TimeRangeToday)
|
||||
timeRange := model.StartOfDayForTimeRange(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, Page: 0, PerPage: 5})
|
||||
topReactions, err := th.App.GetTopReactionsForUserSince(userId, teamId, &model.InsightsOpts{StartUnixMilli: timeRange.UnixMilli(), Page: 0, PerPage: 5})
|
||||
require.Nil(t, err)
|
||||
reactions := topReactions.Items
|
||||
|
||||
@@ -414,7 +414,7 @@ func TestGetTopReactionsForUserSince(t *testing.T) {
|
||||
assert.Equal(t, expectedTopReactions[i].Count, reaction.Count)
|
||||
}
|
||||
|
||||
topReactions, err = th.App.GetTopReactionsForUserSince(userId, teamId, &model.InsightsOpts{StartUnixMilli: timeRange, Page: 1, PerPage: 5})
|
||||
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)
|
||||
@@ -423,7 +423,7 @@ func TestGetTopReactionsForUserSince(t *testing.T) {
|
||||
|
||||
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})
|
||||
_, err := th.App.GetTopReactionsForUserSince(userId, teamId, &model.InsightsOpts{StartUnixMilli: timeRange.UnixMilli(), Page: 0, PerPage: 5})
|
||||
assert.NotNil(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
16
i18n/en.json
16
i18n/en.json
@@ -187,6 +187,10 @@
|
||||
"id": "api.admin.upload_brand_image.too_large.app_error",
|
||||
"translation": "Unable to upload file. File is too large."
|
||||
},
|
||||
{
|
||||
"id": "api.authorization_error.guest",
|
||||
"translation": " "
|
||||
},
|
||||
{
|
||||
"id": "api.back_to_app",
|
||||
"translation": "Back to {{.SiteName}}"
|
||||
@@ -2053,6 +2057,10 @@
|
||||
"id": "api.license_error",
|
||||
"translation": "api endpoint requires a license"
|
||||
},
|
||||
{
|
||||
"id": "api.license_error.professional_or_enterprise",
|
||||
"translation": " "
|
||||
},
|
||||
{
|
||||
"id": "api.marshal_error",
|
||||
"translation": "Failed to marshal."
|
||||
@@ -4531,6 +4539,10 @@
|
||||
"id": "app.channel.get_pinnedpost_count.app_error",
|
||||
"translation": "Unable to get the channel pinned post count."
|
||||
},
|
||||
{
|
||||
"id": "app.channel.get_post_count_by_day.app_error",
|
||||
"translation": " "
|
||||
},
|
||||
{
|
||||
"id": "app.channel.get_private_channels.get.app_error",
|
||||
"translation": "Unable to get private channels."
|
||||
@@ -8531,10 +8543,6 @@
|
||||
"id": "model.incoming_hook.username.app_error",
|
||||
"translation": "Invalid username."
|
||||
},
|
||||
{
|
||||
"id": "model.insights.time_range.app_error",
|
||||
"translation": " "
|
||||
},
|
||||
{
|
||||
"id": "model.job.is_valid.create_at.app_error",
|
||||
"translation": "Create at must be a valid time."
|
||||
|
||||
@@ -4,14 +4,18 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
type PostCountGrouping string
|
||||
|
||||
const (
|
||||
TimeRangeToday string = "today"
|
||||
TimeRange7Day string = "7_day"
|
||||
TimeRange28Day string = "28_day"
|
||||
|
||||
PostsByHour PostCountGrouping = "hour"
|
||||
PostsByDay PostCountGrouping = "day"
|
||||
)
|
||||
|
||||
type InsightsOpts struct {
|
||||
@@ -38,7 +42,16 @@ type TopReaction struct {
|
||||
// Top Channels
|
||||
type TopChannelList struct {
|
||||
InsightsListData
|
||||
Items []*TopChannel `json:"items"`
|
||||
Items []*TopChannel `json:"items"`
|
||||
PostCountByDuration ChannelPostCountByDuration `json:"channel_post_counts_by_duration"`
|
||||
}
|
||||
|
||||
func (t *TopChannelList) ChannelIDs() []string {
|
||||
var ids []string
|
||||
for _, item := range t.Items {
|
||||
ids = append(ids, item.ID)
|
||||
}
|
||||
return ids
|
||||
}
|
||||
|
||||
type TopChannel struct {
|
||||
@@ -50,21 +63,116 @@ type TopChannel struct {
|
||||
MessageCount int64 `json:"message_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()
|
||||
type DurationPostCount struct {
|
||||
ChannelID string `db:"channelid"`
|
||||
// Duration is an ISO8601 date string representing either a day or a day and hour (ex. "2022-05-26" or "2022-05-26T14").
|
||||
Duration string `db:"duration"`
|
||||
PostCount int `db:"postcount"`
|
||||
}
|
||||
|
||||
func TimeRangeToNumberDays(timeRange string) int {
|
||||
var n int
|
||||
switch timeRange {
|
||||
case TimeRangeToday:
|
||||
return GetStartOfDayMillis(now, offset), nil
|
||||
n = 1
|
||||
case TimeRange7Day:
|
||||
return GetStartOfDayMillis(now.Add(time.Hour*time.Duration(-168)), offset), nil
|
||||
n = 7
|
||||
case TimeRange28Day:
|
||||
return GetStartOfDayMillis(now.Add(time.Hour*time.Duration(-672)), offset), nil
|
||||
n = 28
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// ChannelPostCountByDuration contains a count of posts by channel id, grouped by ISO8601 date string.
|
||||
// Example 1 (grouped by day):
|
||||
// cpc := model.ChannelPostCountByDuration{
|
||||
// "2009-11-11": {
|
||||
// "ezbp7nqxzjgdir8riodyafr9ww": 90,
|
||||
// "p949c1xdojfgzffxma3p3s3ikr": 201,
|
||||
// },
|
||||
// "2009-11-12": {
|
||||
// "ezbp7nqxzjgdir8riodyafr9ww": 45,
|
||||
// "p949c1xdojfgzffxma3p3s3ikr": 68,
|
||||
// },
|
||||
// }
|
||||
// Example 2 (grouped by hour):
|
||||
// cpc := model.ChannelPostCountByDuration{
|
||||
// "2009-11-11T01": {
|
||||
// "ezbp7nqxzjgdir8riodyafr9ww": 90,
|
||||
// "p949c1xdojfgzffxma3p3s3ikr": 201,
|
||||
// },
|
||||
// "2009-11-11T02": {
|
||||
// "ezbp7nqxzjgdir8riodyafr9ww": 45,
|
||||
// "p949c1xdojfgzffxma3p3s3ikr": 68,
|
||||
// },
|
||||
// }
|
||||
type ChannelPostCountByDuration map[string]map[string]int
|
||||
|
||||
func blankChannelCountsMap(channelIDs []string) map[string]int {
|
||||
blankChannelCounts := map[string]int{}
|
||||
for _, id := range channelIDs {
|
||||
blankChannelCounts[id] = 0
|
||||
}
|
||||
return blankChannelCounts
|
||||
}
|
||||
|
||||
func ToDailyPostCountViewModel(dpc []*DurationPostCount, startTime *time.Time, numDays int, channelIDs []string) ChannelPostCountByDuration {
|
||||
viewModel := ChannelPostCountByDuration{}
|
||||
|
||||
keyTime := *startTime
|
||||
nowAtLocation := time.Now().In(startTime.Location())
|
||||
|
||||
if numDays == 1 {
|
||||
for keyTime.Before(nowAtLocation) {
|
||||
dateTimeKey := keyTime.Format(time.RFC3339)
|
||||
viewModel[dateTimeKey] = blankChannelCountsMap(channelIDs)
|
||||
keyTime = keyTime.Add(time.Hour)
|
||||
}
|
||||
} else {
|
||||
for keyTime.Before(nowAtLocation) {
|
||||
dateTimeKey := keyTime.Format("2006-01-02")
|
||||
viewModel[dateTimeKey] = blankChannelCountsMap(channelIDs)
|
||||
keyTime = keyTime.Add(24 * time.Hour)
|
||||
}
|
||||
}
|
||||
|
||||
return GetStartOfDayMillis(now, offset), NewAppError("Insights.IsValidRequest", "model.insights.time_range.app_error", nil, "", http.StatusBadRequest)
|
||||
for _, item := range dpc {
|
||||
var parseFormat string
|
||||
var keyFormat string
|
||||
if numDays == 1 {
|
||||
parseFormat = "2006-01-02T15 "
|
||||
keyFormat = time.RFC3339
|
||||
} else {
|
||||
parseFormat = "2006-01-02"
|
||||
keyFormat = parseFormat
|
||||
}
|
||||
durTime, err := time.ParseInLocation(parseFormat, item.Duration, startTime.Location())
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
localizedKey := durTime.Format(keyFormat)
|
||||
_, hasKey := viewModel[localizedKey]
|
||||
if !hasKey {
|
||||
viewModel[localizedKey] = map[string]int{}
|
||||
}
|
||||
viewModel[localizedKey][item.ChannelID] = item.PostCount
|
||||
}
|
||||
|
||||
return viewModel
|
||||
}
|
||||
|
||||
// StartOfDayForTimeRange gets the unix start time in milliseconds from the given time range.
|
||||
// Time range can be one of: "today", "7_day", or "28_day".
|
||||
func StartOfDayForTimeRange(timeRange string, location *time.Location) *time.Time {
|
||||
now := time.Now().In(location)
|
||||
resultTime := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, location)
|
||||
switch timeRange {
|
||||
case TimeRange7Day:
|
||||
resultTime = resultTime.Add(time.Hour * time.Duration(-144))
|
||||
case TimeRange28Day:
|
||||
resultTime = resultTime.Add(time.Hour * time.Duration(-648))
|
||||
}
|
||||
return &resultTime
|
||||
}
|
||||
|
||||
// GetTopReactionListWithPagination adds a rank to each item in the given list of TopReaction and checks if there is
|
||||
|
||||
@@ -9,26 +9,6 @@ import (
|
||||
"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 TestGetTopReactionListWithPagination(t *testing.T) {
|
||||
reactions := []*TopReaction{
|
||||
{EmojiName: "smile", Count: 200},
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
@@ -782,6 +783,14 @@ func (u *User) GetPreferredTimezone() string {
|
||||
return GetPreferredTimezone(u.Timezone)
|
||||
}
|
||||
|
||||
func (u *User) GetTimezoneLocation() *time.Location {
|
||||
loc, _ := time.LoadLocation(u.GetPreferredTimezone())
|
||||
if loc == nil {
|
||||
loc = time.Now().UTC().Location()
|
||||
}
|
||||
return loc
|
||||
}
|
||||
|
||||
// IsRemote returns true if the user belongs to a remote cluster (has RemoteId).
|
||||
func (u *User) IsRemote() bool {
|
||||
return u.RemoteId != nil && *u.RemoteId != ""
|
||||
|
||||
@@ -8,6 +8,7 @@ package opentracinglayer
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/mattermost/mattermost-server/v6/model"
|
||||
"github.com/mattermost/mattermost-server/v6/services/tracing"
|
||||
|
||||
@@ -9,6 +9,7 @@ package retrylayer
|
||||
import (
|
||||
"context"
|
||||
timepkg "time"
|
||||
"time"
|
||||
|
||||
"github.com/lib/pq"
|
||||
"github.com/mattermost/mattermost-server/v6/model"
|
||||
|
||||
@@ -8,7 +8,7 @@ package timerlayer
|
||||
|
||||
import (
|
||||
"context"
|
||||
timemodule "time"
|
||||
"time"
|
||||
|
||||
"github.com/mattermost/mattermost-server/v6/einterfaces"
|
||||
"github.com/mattermost/mattermost-server/v6/model"
|
||||
@@ -38,13 +38,13 @@ type {{.Name}} struct {
|
||||
{{range $substoreName, $substore := .SubStores}}
|
||||
{{range $index, $element := $substore.Methods}}
|
||||
func (s *{{$.Name}}{{$substoreName}}Store) {{$index}}({{$element.Params | joinParamsWithType}}) {{$element.Results | joinResultsForSignature}} {
|
||||
start := timemodule.Now()
|
||||
start := time.Now()
|
||||
{{if $element.Results | len | eq 0}}
|
||||
s.{{$substoreName}}Store.{{$index}}({{$element.Params | joinParams}})
|
||||
{{else}}
|
||||
{{genResultsVars $element.Results false }} := s.{{$substoreName}}Store.{{$index}}({{$element.Params | joinParams}})
|
||||
{{end}}
|
||||
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
|
||||
elapsed := float64(time.Since(start)) / float64(time.Second)
|
||||
if s.Root.Metrics != nil {
|
||||
success := "false"
|
||||
if {{$element.Results | errorToBoolean}} {
|
||||
|
||||
@@ -8,6 +8,7 @@ package opentracinglayer
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/mattermost/mattermost-server/v6/model"
|
||||
"github.com/mattermost/mattermost-server/v6/services/tracing"
|
||||
@@ -745,7 +746,7 @@ func (s *OpenTracingLayerChannelStore) CreateSidebarCategory(userID string, team
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (s *OpenTracingLayerChannelStore) Delete(channelID string, time int64) error {
|
||||
func (s *OpenTracingLayerChannelStore) Delete(channelID string, timestamp int64) error {
|
||||
origCtx := s.Root.Store.Context()
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.Delete")
|
||||
s.Root.Store.SetContext(newCtx)
|
||||
@@ -754,7 +755,7 @@ func (s *OpenTracingLayerChannelStore) Delete(channelID string, time int64) erro
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
err := s.ChannelStore.Delete(channelID, time)
|
||||
err := s.ChannelStore.Delete(channelID, timestamp)
|
||||
if err != nil {
|
||||
span.LogFields(spanlog.Error(err))
|
||||
ext.Error.Set(span, true)
|
||||
@@ -2014,6 +2015,24 @@ func (s *OpenTracingLayerChannelStore) PermanentDeleteMembersByUser(userID strin
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *OpenTracingLayerChannelStore) PostCountsByDuration(channelIDs []string, sinceUnixMillis int64, userID *string, duration model.PostCountGrouping, groupingLocation *time.Location) ([]*model.DurationPostCount, error) {
|
||||
origCtx := s.Root.Store.Context()
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.PostCountsByDuration")
|
||||
s.Root.Store.SetContext(newCtx)
|
||||
defer func() {
|
||||
s.Root.Store.SetContext(origCtx)
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
result, err := s.ChannelStore.PostCountsByDuration(channelIDs, sinceUnixMillis, userID, duration, groupingLocation)
|
||||
if err != nil {
|
||||
span.LogFields(spanlog.Error(err))
|
||||
ext.Error.Set(span, true)
|
||||
}
|
||||
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (s *OpenTracingLayerChannelStore) RemoveAllDeactivatedMembers(channelID string) error {
|
||||
origCtx := s.Root.Store.Context()
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.RemoveAllDeactivatedMembers")
|
||||
@@ -2086,7 +2105,7 @@ func (s *OpenTracingLayerChannelStore) ResetAllChannelSchemes() error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *OpenTracingLayerChannelStore) Restore(channelID string, time int64) error {
|
||||
func (s *OpenTracingLayerChannelStore) Restore(channelID string, timestamp int64) error {
|
||||
origCtx := s.Root.Store.Context()
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.Restore")
|
||||
s.Root.Store.SetContext(newCtx)
|
||||
@@ -2095,7 +2114,7 @@ func (s *OpenTracingLayerChannelStore) Restore(channelID string, time int64) err
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
err := s.ChannelStore.Restore(channelID, time)
|
||||
err := s.ChannelStore.Restore(channelID, timestamp)
|
||||
if err != nil {
|
||||
span.LogFields(spanlog.Error(err))
|
||||
ext.Error.Set(span, true)
|
||||
@@ -2788,7 +2807,7 @@ func (s *OpenTracingLayerCommandStore) AnalyticsCommandCount(teamID string) (int
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (s *OpenTracingLayerCommandStore) Delete(commandID string, time int64) error {
|
||||
func (s *OpenTracingLayerCommandStore) Delete(commandID string, timestamp int64) error {
|
||||
origCtx := s.Root.Store.Context()
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "CommandStore.Delete")
|
||||
s.Root.Store.SetContext(newCtx)
|
||||
@@ -2797,7 +2816,7 @@ func (s *OpenTracingLayerCommandStore) Delete(commandID string, time int64) erro
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
err := s.CommandStore.Delete(commandID, time)
|
||||
err := s.CommandStore.Delete(commandID, timestamp)
|
||||
if err != nil {
|
||||
span.LogFields(spanlog.Error(err))
|
||||
ext.Error.Set(span, true)
|
||||
@@ -3107,7 +3126,7 @@ func (s *OpenTracingLayerComplianceStore) Update(compliance *model.Compliance) (
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (s *OpenTracingLayerEmojiStore) Delete(emoji *model.Emoji, time int64) error {
|
||||
func (s *OpenTracingLayerEmojiStore) Delete(emoji *model.Emoji, timestamp int64) error {
|
||||
origCtx := s.Root.Store.Context()
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "EmojiStore.Delete")
|
||||
s.Root.Store.SetContext(newCtx)
|
||||
@@ -3116,7 +3135,7 @@ func (s *OpenTracingLayerEmojiStore) Delete(emoji *model.Emoji, time int64) erro
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
err := s.EmojiStore.Delete(emoji, time)
|
||||
err := s.EmojiStore.Delete(emoji, timestamp)
|
||||
if err != nil {
|
||||
span.LogFields(spanlog.Error(err))
|
||||
ext.Error.Set(span, true)
|
||||
@@ -5450,7 +5469,7 @@ func (s *OpenTracingLayerPostStore) ClearCaches() {
|
||||
|
||||
}
|
||||
|
||||
func (s *OpenTracingLayerPostStore) Delete(postID string, time int64, deleteByID string) error {
|
||||
func (s *OpenTracingLayerPostStore) Delete(postID string, timestamp int64, deleteByID string) error {
|
||||
origCtx := s.Root.Store.Context()
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "PostStore.Delete")
|
||||
s.Root.Store.SetContext(newCtx)
|
||||
@@ -5459,7 +5478,7 @@ func (s *OpenTracingLayerPostStore) Delete(postID string, time int64, deleteByID
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
err := s.PostStore.Delete(postID, time, deleteByID)
|
||||
err := s.PostStore.Delete(postID, timestamp, deleteByID)
|
||||
if err != nil {
|
||||
span.LogFields(spanlog.Error(err))
|
||||
ext.Error.Set(span, true)
|
||||
@@ -5682,7 +5701,7 @@ func (s *OpenTracingLayerPostStore) GetParentsForExportAfter(limit int, afterID
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (s *OpenTracingLayerPostStore) GetPostAfterTime(channelID string, time int64, collapsedThreads bool) (*model.Post, error) {
|
||||
func (s *OpenTracingLayerPostStore) GetPostAfterTime(channelID string, timestamp int64, collapsedThreads bool) (*model.Post, error) {
|
||||
origCtx := s.Root.Store.Context()
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "PostStore.GetPostAfterTime")
|
||||
s.Root.Store.SetContext(newCtx)
|
||||
@@ -5691,7 +5710,7 @@ func (s *OpenTracingLayerPostStore) GetPostAfterTime(channelID string, time int6
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
result, err := s.PostStore.GetPostAfterTime(channelID, time, collapsedThreads)
|
||||
result, err := s.PostStore.GetPostAfterTime(channelID, timestamp, collapsedThreads)
|
||||
if err != nil {
|
||||
span.LogFields(spanlog.Error(err))
|
||||
ext.Error.Set(span, true)
|
||||
@@ -5700,7 +5719,7 @@ func (s *OpenTracingLayerPostStore) GetPostAfterTime(channelID string, time int6
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (s *OpenTracingLayerPostStore) GetPostIdAfterTime(channelID string, time int64, collapsedThreads bool) (string, error) {
|
||||
func (s *OpenTracingLayerPostStore) GetPostIdAfterTime(channelID string, timestamp int64, collapsedThreads bool) (string, error) {
|
||||
origCtx := s.Root.Store.Context()
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "PostStore.GetPostIdAfterTime")
|
||||
s.Root.Store.SetContext(newCtx)
|
||||
@@ -5709,7 +5728,7 @@ func (s *OpenTracingLayerPostStore) GetPostIdAfterTime(channelID string, time in
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
result, err := s.PostStore.GetPostIdAfterTime(channelID, time, collapsedThreads)
|
||||
result, err := s.PostStore.GetPostIdAfterTime(channelID, timestamp, collapsedThreads)
|
||||
if err != nil {
|
||||
span.LogFields(spanlog.Error(err))
|
||||
ext.Error.Set(span, true)
|
||||
@@ -5718,7 +5737,7 @@ func (s *OpenTracingLayerPostStore) GetPostIdAfterTime(channelID string, time in
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (s *OpenTracingLayerPostStore) GetPostIdBeforeTime(channelID string, time int64, collapsedThreads bool) (string, error) {
|
||||
func (s *OpenTracingLayerPostStore) GetPostIdBeforeTime(channelID string, timestamp int64, collapsedThreads bool) (string, error) {
|
||||
origCtx := s.Root.Store.Context()
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "PostStore.GetPostIdBeforeTime")
|
||||
s.Root.Store.SetContext(newCtx)
|
||||
@@ -5727,7 +5746,7 @@ func (s *OpenTracingLayerPostStore) GetPostIdBeforeTime(channelID string, time i
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
result, err := s.PostStore.GetPostIdBeforeTime(channelID, time, collapsedThreads)
|
||||
result, err := s.PostStore.GetPostIdBeforeTime(channelID, timestamp, collapsedThreads)
|
||||
if err != nil {
|
||||
span.LogFields(spanlog.Error(err))
|
||||
ext.Error.Set(span, true)
|
||||
@@ -5826,7 +5845,7 @@ func (s *OpenTracingLayerPostStore) GetPostsByIds(postIds []string) ([]*model.Po
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (s *OpenTracingLayerPostStore) GetPostsCreatedAt(channelID string, time int64) ([]*model.Post, error) {
|
||||
func (s *OpenTracingLayerPostStore) GetPostsCreatedAt(channelID string, timestamp int64) ([]*model.Post, error) {
|
||||
origCtx := s.Root.Store.Context()
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "PostStore.GetPostsCreatedAt")
|
||||
s.Root.Store.SetContext(newCtx)
|
||||
@@ -5835,7 +5854,7 @@ func (s *OpenTracingLayerPostStore) GetPostsCreatedAt(channelID string, time int
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
result, err := s.PostStore.GetPostsCreatedAt(channelID, time)
|
||||
result, err := s.PostStore.GetPostsCreatedAt(channelID, timestamp)
|
||||
if err != nil {
|
||||
span.LogFields(spanlog.Error(err))
|
||||
ext.Error.Set(span, true)
|
||||
@@ -7639,7 +7658,7 @@ func (s *OpenTracingLayerSessionStore) UpdateExpiredNotify(sessionid string, not
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *OpenTracingLayerSessionStore) UpdateExpiresAt(sessionID string, time int64) error {
|
||||
func (s *OpenTracingLayerSessionStore) UpdateExpiresAt(sessionID string, timestamp int64) error {
|
||||
origCtx := s.Root.Store.Context()
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "SessionStore.UpdateExpiresAt")
|
||||
s.Root.Store.SetContext(newCtx)
|
||||
@@ -7648,7 +7667,7 @@ func (s *OpenTracingLayerSessionStore) UpdateExpiresAt(sessionID string, time in
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
err := s.SessionStore.UpdateExpiresAt(sessionID, time)
|
||||
err := s.SessionStore.UpdateExpiresAt(sessionID, timestamp)
|
||||
if err != nil {
|
||||
span.LogFields(spanlog.Error(err))
|
||||
ext.Error.Set(span, true)
|
||||
@@ -7657,7 +7676,7 @@ func (s *OpenTracingLayerSessionStore) UpdateExpiresAt(sessionID string, time in
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *OpenTracingLayerSessionStore) UpdateLastActivityAt(sessionID string, time int64) error {
|
||||
func (s *OpenTracingLayerSessionStore) UpdateLastActivityAt(sessionID string, timestamp int64) error {
|
||||
origCtx := s.Root.Store.Context()
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "SessionStore.UpdateLastActivityAt")
|
||||
s.Root.Store.SetContext(newCtx)
|
||||
@@ -7666,7 +7685,7 @@ func (s *OpenTracingLayerSessionStore) UpdateLastActivityAt(sessionID string, ti
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
err := s.SessionStore.UpdateLastActivityAt(sessionID, time)
|
||||
err := s.SessionStore.UpdateLastActivityAt(sessionID, timestamp)
|
||||
if err != nil {
|
||||
span.LogFields(spanlog.Error(err))
|
||||
ext.Error.Set(span, true)
|
||||
@@ -10000,7 +10019,7 @@ func (s *OpenTracingLayerUploadSessionStore) Update(session *model.UploadSession
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *OpenTracingLayerUserStore) AnalyticsActiveCount(time int64, options model.UserCountOptions) (int64, error) {
|
||||
func (s *OpenTracingLayerUserStore) AnalyticsActiveCount(timestamp int64, options model.UserCountOptions) (int64, error) {
|
||||
origCtx := s.Root.Store.Context()
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "UserStore.AnalyticsActiveCount")
|
||||
s.Root.Store.SetContext(newCtx)
|
||||
@@ -10009,7 +10028,7 @@ func (s *OpenTracingLayerUserStore) AnalyticsActiveCount(time int64, options mod
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
result, err := s.UserStore.AnalyticsActiveCount(time, options)
|
||||
result, err := s.UserStore.AnalyticsActiveCount(timestamp, options)
|
||||
if err != nil {
|
||||
span.LogFields(spanlog.Error(err))
|
||||
ext.Error.Set(span, true)
|
||||
@@ -11598,7 +11617,7 @@ func (s *OpenTracingLayerWebhookStore) ClearCaches() {
|
||||
|
||||
}
|
||||
|
||||
func (s *OpenTracingLayerWebhookStore) DeleteIncoming(webhookID string, time int64) error {
|
||||
func (s *OpenTracingLayerWebhookStore) DeleteIncoming(webhookID string, timestamp int64) error {
|
||||
origCtx := s.Root.Store.Context()
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "WebhookStore.DeleteIncoming")
|
||||
s.Root.Store.SetContext(newCtx)
|
||||
@@ -11607,7 +11626,7 @@ func (s *OpenTracingLayerWebhookStore) DeleteIncoming(webhookID string, time int
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
err := s.WebhookStore.DeleteIncoming(webhookID, time)
|
||||
err := s.WebhookStore.DeleteIncoming(webhookID, timestamp)
|
||||
if err != nil {
|
||||
span.LogFields(spanlog.Error(err))
|
||||
ext.Error.Set(span, true)
|
||||
@@ -11616,7 +11635,7 @@ func (s *OpenTracingLayerWebhookStore) DeleteIncoming(webhookID string, time int
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *OpenTracingLayerWebhookStore) DeleteOutgoing(webhookID string, time int64) error {
|
||||
func (s *OpenTracingLayerWebhookStore) DeleteOutgoing(webhookID string, timestamp int64) error {
|
||||
origCtx := s.Root.Store.Context()
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "WebhookStore.DeleteOutgoing")
|
||||
s.Root.Store.SetContext(newCtx)
|
||||
@@ -11625,7 +11644,7 @@ func (s *OpenTracingLayerWebhookStore) DeleteOutgoing(webhookID string, time int
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
err := s.WebhookStore.DeleteOutgoing(webhookID, time)
|
||||
err := s.WebhookStore.DeleteOutgoing(webhookID, timestamp)
|
||||
if err != nil {
|
||||
span.LogFields(spanlog.Error(err))
|
||||
ext.Error.Set(span, true)
|
||||
|
||||
@@ -8,6 +8,7 @@ package retrylayer
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
timepkg "time"
|
||||
|
||||
"github.com/go-sql-driver/mysql"
|
||||
@@ -814,11 +815,11 @@ func (s *RetryLayerChannelStore) CreateSidebarCategory(userID string, teamID str
|
||||
|
||||
}
|
||||
|
||||
func (s *RetryLayerChannelStore) Delete(channelID string, time int64) error {
|
||||
func (s *RetryLayerChannelStore) Delete(channelID string, timestamp int64) error {
|
||||
|
||||
tries := 0
|
||||
for {
|
||||
err := s.ChannelStore.Delete(channelID, time)
|
||||
err := s.ChannelStore.Delete(channelID, timestamp)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
@@ -2212,6 +2213,27 @@ func (s *RetryLayerChannelStore) PermanentDeleteMembersByUser(userID string) err
|
||||
|
||||
}
|
||||
|
||||
func (s *RetryLayerChannelStore) PostCountsByDuration(channelIDs []string, sinceUnixMillis int64, userID *string, duration model.PostCountGrouping, groupingLocation *time.Location) ([]*model.DurationPostCount, error) {
|
||||
|
||||
tries := 0
|
||||
for {
|
||||
result, err := s.ChannelStore.PostCountsByDuration(channelIDs, sinceUnixMillis, userID, duration, groupingLocation)
|
||||
if err == nil {
|
||||
return result, nil
|
||||
}
|
||||
if !isRepeatableError(err) {
|
||||
return result, err
|
||||
}
|
||||
tries++
|
||||
if tries >= 3 {
|
||||
err = errors.Wrap(err, "giving up after 3 consecutive repeatable transaction failures")
|
||||
return result, err
|
||||
}
|
||||
timepkg.Sleep(100 * timepkg.Millisecond)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (s *RetryLayerChannelStore) RemoveAllDeactivatedMembers(channelID string) error {
|
||||
|
||||
tries := 0
|
||||
@@ -2296,11 +2318,11 @@ func (s *RetryLayerChannelStore) ResetAllChannelSchemes() error {
|
||||
|
||||
}
|
||||
|
||||
func (s *RetryLayerChannelStore) Restore(channelID string, time int64) error {
|
||||
func (s *RetryLayerChannelStore) Restore(channelID string, timestamp int64) error {
|
||||
|
||||
tries := 0
|
||||
for {
|
||||
err := s.ChannelStore.Restore(channelID, time)
|
||||
err := s.ChannelStore.Restore(channelID, timestamp)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
@@ -3115,11 +3137,11 @@ func (s *RetryLayerCommandStore) AnalyticsCommandCount(teamID string) (int64, er
|
||||
|
||||
}
|
||||
|
||||
func (s *RetryLayerCommandStore) Delete(commandID string, time int64) error {
|
||||
func (s *RetryLayerCommandStore) Delete(commandID string, timestamp int64) error {
|
||||
|
||||
tries := 0
|
||||
for {
|
||||
err := s.CommandStore.Delete(commandID, time)
|
||||
err := s.CommandStore.Delete(commandID, timestamp)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
@@ -3478,11 +3500,11 @@ func (s *RetryLayerComplianceStore) Update(compliance *model.Compliance) (*model
|
||||
|
||||
}
|
||||
|
||||
func (s *RetryLayerEmojiStore) Delete(emoji *model.Emoji, time int64) error {
|
||||
func (s *RetryLayerEmojiStore) Delete(emoji *model.Emoji, timestamp int64) error {
|
||||
|
||||
tries := 0
|
||||
for {
|
||||
err := s.EmojiStore.Delete(emoji, time)
|
||||
err := s.EmojiStore.Delete(emoji, timestamp)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
@@ -6184,11 +6206,11 @@ func (s *RetryLayerPostStore) ClearCaches() {
|
||||
|
||||
}
|
||||
|
||||
func (s *RetryLayerPostStore) Delete(postID string, time int64, deleteByID string) error {
|
||||
func (s *RetryLayerPostStore) Delete(postID string, timestamp int64, deleteByID string) error {
|
||||
|
||||
tries := 0
|
||||
for {
|
||||
err := s.PostStore.Delete(postID, time, deleteByID)
|
||||
err := s.PostStore.Delete(postID, timestamp, deleteByID)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
@@ -6427,11 +6449,11 @@ func (s *RetryLayerPostStore) GetParentsForExportAfter(limit int, afterID string
|
||||
|
||||
}
|
||||
|
||||
func (s *RetryLayerPostStore) GetPostAfterTime(channelID string, time int64, collapsedThreads bool) (*model.Post, error) {
|
||||
func (s *RetryLayerPostStore) GetPostAfterTime(channelID string, timestamp int64, collapsedThreads bool) (*model.Post, error) {
|
||||
|
||||
tries := 0
|
||||
for {
|
||||
result, err := s.PostStore.GetPostAfterTime(channelID, time, collapsedThreads)
|
||||
result, err := s.PostStore.GetPostAfterTime(channelID, timestamp, collapsedThreads)
|
||||
if err == nil {
|
||||
return result, nil
|
||||
}
|
||||
@@ -6448,11 +6470,11 @@ func (s *RetryLayerPostStore) GetPostAfterTime(channelID string, time int64, col
|
||||
|
||||
}
|
||||
|
||||
func (s *RetryLayerPostStore) GetPostIdAfterTime(channelID string, time int64, collapsedThreads bool) (string, error) {
|
||||
func (s *RetryLayerPostStore) GetPostIdAfterTime(channelID string, timestamp int64, collapsedThreads bool) (string, error) {
|
||||
|
||||
tries := 0
|
||||
for {
|
||||
result, err := s.PostStore.GetPostIdAfterTime(channelID, time, collapsedThreads)
|
||||
result, err := s.PostStore.GetPostIdAfterTime(channelID, timestamp, collapsedThreads)
|
||||
if err == nil {
|
||||
return result, nil
|
||||
}
|
||||
@@ -6469,11 +6491,11 @@ func (s *RetryLayerPostStore) GetPostIdAfterTime(channelID string, time int64, c
|
||||
|
||||
}
|
||||
|
||||
func (s *RetryLayerPostStore) GetPostIdBeforeTime(channelID string, time int64, collapsedThreads bool) (string, error) {
|
||||
func (s *RetryLayerPostStore) GetPostIdBeforeTime(channelID string, timestamp int64, collapsedThreads bool) (string, error) {
|
||||
|
||||
tries := 0
|
||||
for {
|
||||
result, err := s.PostStore.GetPostIdBeforeTime(channelID, time, collapsedThreads)
|
||||
result, err := s.PostStore.GetPostIdBeforeTime(channelID, timestamp, collapsedThreads)
|
||||
if err == nil {
|
||||
return result, nil
|
||||
}
|
||||
@@ -6595,11 +6617,11 @@ func (s *RetryLayerPostStore) GetPostsByIds(postIds []string) ([]*model.Post, er
|
||||
|
||||
}
|
||||
|
||||
func (s *RetryLayerPostStore) GetPostsCreatedAt(channelID string, time int64) ([]*model.Post, error) {
|
||||
func (s *RetryLayerPostStore) GetPostsCreatedAt(channelID string, timestamp int64) ([]*model.Post, error) {
|
||||
|
||||
tries := 0
|
||||
for {
|
||||
result, err := s.PostStore.GetPostsCreatedAt(channelID, time)
|
||||
result, err := s.PostStore.GetPostsCreatedAt(channelID, timestamp)
|
||||
if err == nil {
|
||||
return result, nil
|
||||
}
|
||||
@@ -8701,11 +8723,11 @@ func (s *RetryLayerSessionStore) UpdateExpiredNotify(sessionid string, notified
|
||||
|
||||
}
|
||||
|
||||
func (s *RetryLayerSessionStore) UpdateExpiresAt(sessionID string, time int64) error {
|
||||
func (s *RetryLayerSessionStore) UpdateExpiresAt(sessionID string, timestamp int64) error {
|
||||
|
||||
tries := 0
|
||||
for {
|
||||
err := s.SessionStore.UpdateExpiresAt(sessionID, time)
|
||||
err := s.SessionStore.UpdateExpiresAt(sessionID, timestamp)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
@@ -8722,11 +8744,11 @@ func (s *RetryLayerSessionStore) UpdateExpiresAt(sessionID string, time int64) e
|
||||
|
||||
}
|
||||
|
||||
func (s *RetryLayerSessionStore) UpdateLastActivityAt(sessionID string, time int64) error {
|
||||
func (s *RetryLayerSessionStore) UpdateLastActivityAt(sessionID string, timestamp int64) error {
|
||||
|
||||
tries := 0
|
||||
for {
|
||||
err := s.SessionStore.UpdateLastActivityAt(sessionID, time)
|
||||
err := s.SessionStore.UpdateLastActivityAt(sessionID, timestamp)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
@@ -11428,11 +11450,11 @@ func (s *RetryLayerUploadSessionStore) Update(session *model.UploadSession) erro
|
||||
|
||||
}
|
||||
|
||||
func (s *RetryLayerUserStore) AnalyticsActiveCount(time int64, options model.UserCountOptions) (int64, error) {
|
||||
func (s *RetryLayerUserStore) AnalyticsActiveCount(timestamp int64, options model.UserCountOptions) (int64, error) {
|
||||
|
||||
tries := 0
|
||||
for {
|
||||
result, err := s.UserStore.AnalyticsActiveCount(time, options)
|
||||
result, err := s.UserStore.AnalyticsActiveCount(timestamp, options)
|
||||
if err == nil {
|
||||
return result, nil
|
||||
}
|
||||
@@ -13219,11 +13241,11 @@ func (s *RetryLayerWebhookStore) ClearCaches() {
|
||||
|
||||
}
|
||||
|
||||
func (s *RetryLayerWebhookStore) DeleteIncoming(webhookID string, time int64) error {
|
||||
func (s *RetryLayerWebhookStore) DeleteIncoming(webhookID string, timestamp int64) error {
|
||||
|
||||
tries := 0
|
||||
for {
|
||||
err := s.WebhookStore.DeleteIncoming(webhookID, time)
|
||||
err := s.WebhookStore.DeleteIncoming(webhookID, timestamp)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
@@ -13240,11 +13262,11 @@ func (s *RetryLayerWebhookStore) DeleteIncoming(webhookID string, time int64) er
|
||||
|
||||
}
|
||||
|
||||
func (s *RetryLayerWebhookStore) DeleteOutgoing(webhookID string, time int64) error {
|
||||
func (s *RetryLayerWebhookStore) DeleteOutgoing(webhookID string, timestamp int64) error {
|
||||
|
||||
tries := 0
|
||||
for {
|
||||
err := s.WebhookStore.DeleteOutgoing(webhookID, time)
|
||||
err := s.WebhookStore.DeleteOutgoing(webhookID, timestamp)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -4297,3 +4297,53 @@ func (s SqlChannelStore) GetTopChannelsForUserSince(userID string, teamID string
|
||||
|
||||
return model.GetTopChannelListWithPagination(channels, limit), nil
|
||||
}
|
||||
|
||||
func (s SqlChannelStore) PostCountsByDuration(channelIDs []string, sinceUnixMillis int64, userID *string, duration model.PostCountGrouping, atLocation *time.Location) ([]*model.DurationPostCount, error) {
|
||||
var unixSelect string
|
||||
var propsQuery string
|
||||
loc := atLocation.String()
|
||||
if loc == "Local" {
|
||||
loc = "UTC"
|
||||
}
|
||||
if s.DriverName() == model.DatabaseDriverMysql {
|
||||
if duration == model.PostsByDay {
|
||||
unixSelect = `DATE_FORMAT(CONVERT_TZ(FROM_UNIXTIME(Posts.CreateAt / 1000), 'GMT', '` + loc + `'),'%Y-%m-%d') AS duration`
|
||||
} else {
|
||||
unixSelect = `DATE_FORMAT(CONVERT_TZ(FROM_UNIXTIME(Posts.CreateAt / 1000), 'GMT', '` + loc + `'),'%Y-%m-%dT%H') AS duration`
|
||||
}
|
||||
propsQuery = `(JSON_EXTRACT(Posts.Props, '$.from_bot') IS NULL OR JSON_EXTRACT(Posts.Props, '$.from_bot') = 'false')`
|
||||
} else if s.DriverName() == model.DatabaseDriverPostgres {
|
||||
if duration == model.PostsByDay {
|
||||
unixSelect = fmt.Sprintf(`TO_CHAR(TO_TIMESTAMP(Posts.CreateAt / 1000) AT TIME ZONE '%s', 'YYYY-MM-DD') AS duration`, loc)
|
||||
} else {
|
||||
unixSelect = fmt.Sprintf(`TO_CHAR(TO_TIMESTAMP(Posts.CreateAt / 1000) AT TIME ZONE '%s', 'YYYY-MM-DD"T"HH24') AS duration`, loc)
|
||||
}
|
||||
propsQuery = `(Posts.Props ->> 'from_bot' IS NULL OR Posts.Props ->> 'from_bot' = 'false')`
|
||||
}
|
||||
query := sq.
|
||||
Select("Posts.ChannelId AS channelid", unixSelect, "count(Posts.Id) AS postcount").
|
||||
From("Posts").
|
||||
LeftJoin("Channels ON Posts.ChannelId = Channels.Id").
|
||||
Where(sq.And{
|
||||
sq.Eq{"Posts.DeleteAt": 0},
|
||||
sq.Gt{"Posts.CreateAt": sinceUnixMillis},
|
||||
sq.Eq{"Posts.Type": ""},
|
||||
sq.Eq{"Channels.Id": channelIDs},
|
||||
}).
|
||||
Where(propsQuery).
|
||||
GroupBy("channelid", "duration").
|
||||
OrderBy("channelid", "duration")
|
||||
if userID != nil && model.IsValidId(*userID) {
|
||||
query = query.Where(sq.And{sq.Eq{"Posts.UserId": *userID}})
|
||||
}
|
||||
queryString, args, err := query.ToSql()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to parse query")
|
||||
}
|
||||
dailyPostCounts := make([]*model.DurationPostCount, 0)
|
||||
if err := s.GetReplicaX().Select(&dailyPostCounts, queryString, args...); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to get post counts by duration")
|
||||
}
|
||||
|
||||
return dailyPostCounts, nil
|
||||
}
|
||||
|
||||
@@ -178,8 +178,8 @@ type ChannelStore interface {
|
||||
GetMany(ids []string, allowFromCache bool) (model.ChannelList, error)
|
||||
InvalidateChannel(id string)
|
||||
InvalidateChannelByName(teamID, name string)
|
||||
Delete(channelID string, time int64) error
|
||||
Restore(channelID string, time int64) error
|
||||
Delete(channelID string, timestamp int64) error
|
||||
Restore(channelID string, timestamp int64) error
|
||||
SetDeleteAt(channelID string, deleteAt int64, updateAt int64) error
|
||||
PermanentDelete(channelID string) error
|
||||
PermanentDeleteByTeam(teamID string) error
|
||||
@@ -293,6 +293,7 @@ type ChannelStore interface {
|
||||
// Insights
|
||||
GetTopChannelsForTeamSince(teamID string, userID string, since int64, offset int, limit int) (*model.TopChannelList, error)
|
||||
GetTopChannelsForUserSince(userID string, teamID string, since int64, offset int, limit int) (*model.TopChannelList, error)
|
||||
PostCountsByDuration(channelIDs []string, sinceUnixMillis int64, userID *string, duration model.PostCountGrouping, groupingLocation *time.Location) ([]*model.DurationPostCount, error)
|
||||
}
|
||||
|
||||
type ChannelMemberHistoryStore interface {
|
||||
@@ -338,7 +339,7 @@ type PostStore interface {
|
||||
Update(newPost *model.Post, oldPost *model.Post) (*model.Post, error)
|
||||
Get(ctx context.Context, id string, opts model.GetPostsOptions, userID string, sanitizeOptions map[string]bool) (*model.PostList, error)
|
||||
GetSingle(id string, inclDeleted bool) (*model.Post, error)
|
||||
Delete(postID string, time int64, deleteByID string) error
|
||||
Delete(postID string, timestamp int64, deleteByID string) error
|
||||
PermanentDeleteByUser(userID string) error
|
||||
PermanentDeleteByChannel(channelID string) error
|
||||
GetPosts(options model.GetPostsOptions, allowFromCache bool, sanitizeOptions map[string]bool) (*model.PostList, error)
|
||||
@@ -349,9 +350,9 @@ type PostStore interface {
|
||||
GetPostsBefore(options model.GetPostsOptions, sanitizeOptions map[string]bool) (*model.PostList, error)
|
||||
GetPostsAfter(options model.GetPostsOptions, sanitizeOptions map[string]bool) (*model.PostList, error)
|
||||
GetPostsSince(options model.GetPostsSinceOptions, allowFromCache bool, sanitizeOptions map[string]bool) (*model.PostList, error)
|
||||
GetPostAfterTime(channelID string, time int64, collapsedThreads bool) (*model.Post, error)
|
||||
GetPostIdAfterTime(channelID string, time int64, collapsedThreads bool) (string, error)
|
||||
GetPostIdBeforeTime(channelID string, time int64, collapsedThreads bool) (string, error)
|
||||
GetPostAfterTime(channelID string, timestamp int64, collapsedThreads bool) (*model.Post, error)
|
||||
GetPostIdAfterTime(channelID string, timestamp int64, collapsedThreads bool) (string, error)
|
||||
GetPostIdBeforeTime(channelID string, timestamp int64, collapsedThreads bool) (string, error)
|
||||
GetEtag(channelID string, allowFromCache bool, collapsedThreads bool) string
|
||||
Search(teamID string, userID string, params *model.SearchParams) (*model.PostList, error)
|
||||
AnalyticsUserCountsWithPostsByDay(teamID string) (model.AnalyticsRows, error)
|
||||
@@ -360,7 +361,7 @@ type PostStore interface {
|
||||
ClearCaches()
|
||||
InvalidateLastPostTimeCache(channelID string)
|
||||
GetLastPostRowCreateAt() (int64, error)
|
||||
GetPostsCreatedAt(channelID string, time int64) ([]*model.Post, error)
|
||||
GetPostsCreatedAt(channelID string, timestamp int64) ([]*model.Post, error)
|
||||
Overwrite(post *model.Post) (*model.Post, error)
|
||||
OverwriteMultiple(posts []*model.Post) ([]*model.Post, int, error)
|
||||
GetPostsByIds(postIds []string) ([]*model.Post, error)
|
||||
@@ -422,7 +423,7 @@ type UserStore interface {
|
||||
UpdateFailedPasswordAttempts(userID string, attempts int) error
|
||||
GetSystemAdminProfiles() (map[string]*model.User, error)
|
||||
PermanentDelete(userID string) error
|
||||
AnalyticsActiveCount(time int64, options model.UserCountOptions) (int64, error)
|
||||
AnalyticsActiveCount(timestamp int64, options model.UserCountOptions) (int64, error)
|
||||
AnalyticsActiveCountForPeriod(startTime int64, endTime int64, options model.UserCountOptions) (int64, error)
|
||||
GetUnreadCount(userID string) (int64, error)
|
||||
GetUnreadCountForChannel(userID string, channelID string) (int64, error)
|
||||
@@ -478,8 +479,8 @@ type SessionStore interface {
|
||||
RemoveAllSessions() error
|
||||
PermanentDeleteSessionsByUser(teamID string) error
|
||||
GetLastSessionRowCreateAt() (int64, error)
|
||||
UpdateExpiresAt(sessionID string, time int64) error
|
||||
UpdateLastActivityAt(sessionID string, time int64) error
|
||||
UpdateExpiresAt(sessionID string, timestamp int64) error
|
||||
UpdateLastActivityAt(sessionID string, timestamp int64) error
|
||||
UpdateRoles(userID string, roles string) (string, error)
|
||||
UpdateDeviceId(id string, deviceID string, expiresAt int64) (string, error)
|
||||
UpdateProps(session *model.Session) error
|
||||
@@ -563,7 +564,7 @@ type WebhookStore interface {
|
||||
GetIncomingByTeamByUser(teamID string, userID string, offset, limit int) ([]*model.IncomingWebhook, error)
|
||||
UpdateIncoming(webhook *model.IncomingWebhook) (*model.IncomingWebhook, error)
|
||||
GetIncomingByChannel(channelID string) ([]*model.IncomingWebhook, error)
|
||||
DeleteIncoming(webhookID string, time int64) error
|
||||
DeleteIncoming(webhookID string, timestamp int64) error
|
||||
PermanentDeleteIncomingByChannel(channelID string) error
|
||||
PermanentDeleteIncomingByUser(userID string) error
|
||||
|
||||
@@ -575,7 +576,7 @@ type WebhookStore interface {
|
||||
GetOutgoingListByUser(userID string, offset, limit int) ([]*model.OutgoingWebhook, error)
|
||||
GetOutgoingByTeam(teamID string, offset, limit int) ([]*model.OutgoingWebhook, error)
|
||||
GetOutgoingByTeamByUser(teamID string, userID string, offset, limit int) ([]*model.OutgoingWebhook, error)
|
||||
DeleteOutgoing(webhookID string, time int64) error
|
||||
DeleteOutgoing(webhookID string, timestamp int64) error
|
||||
PermanentDeleteOutgoingByChannel(channelID string) error
|
||||
PermanentDeleteOutgoingByUser(userID string) error
|
||||
UpdateOutgoing(hook *model.OutgoingWebhook) (*model.OutgoingWebhook, error)
|
||||
@@ -591,7 +592,7 @@ type CommandStore interface {
|
||||
GetByTrigger(teamID string, trigger string) (*model.Command, error)
|
||||
Get(id string) (*model.Command, error)
|
||||
GetByTeam(teamID string) ([]*model.Command, error)
|
||||
Delete(commandID string, time int64) error
|
||||
Delete(commandID string, timestamp int64) error
|
||||
PermanentDeleteByTeam(teamID string) error
|
||||
PermanentDeleteByUser(userID string) error
|
||||
Update(hook *model.Command) (*model.Command, error)
|
||||
@@ -639,7 +640,7 @@ type EmojiStore interface {
|
||||
GetByName(ctx context.Context, name string, allowFromCache bool) (*model.Emoji, error)
|
||||
GetMultipleByName(names []string) ([]*model.Emoji, error)
|
||||
GetList(offset, limit int, sort string) ([]*model.Emoji, error)
|
||||
Delete(emoji *model.Emoji, time int64) error
|
||||
Delete(emoji *model.Emoji, timestamp int64) error
|
||||
Search(name string, prefixOnly bool, limit int) ([]*model.Emoji, error)
|
||||
}
|
||||
|
||||
|
||||
@@ -148,6 +148,7 @@ func TestChannelStore(t *testing.T, ss store.Store, s SqlStore) {
|
||||
t.Run("UpdateSidebarChannelsByPreferences", func(t *testing.T) { testUpdateSidebarChannelsByPreferences(t, ss) })
|
||||
t.Run("SetShared", func(t *testing.T) { testSetShared(t, ss) })
|
||||
t.Run("GetTeamForChannel", func(t *testing.T) { testGetTeamForChannel(t, ss) })
|
||||
t.Run("PostCountsByDuration", func(t *testing.T) { testChannelPostCountsByDuration(t, ss) })
|
||||
}
|
||||
|
||||
func testChannelStoreSave(t *testing.T, ss store.Store) {
|
||||
@@ -7904,3 +7905,38 @@ func testGetTeamForChannel(t *testing.T, ss store.Store) {
|
||||
var nfErr *store.ErrNotFound
|
||||
require.True(t, errors.As(err, &nfErr))
|
||||
}
|
||||
|
||||
func testChannelPostCountsByDuration(t *testing.T, ss store.Store) {
|
||||
team, err := ss.Team().Save(&model.Team{
|
||||
Name: model.NewId(),
|
||||
DisplayName: "DisplayName",
|
||||
Email: MakeEmail(),
|
||||
Type: model.TeamOpen,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
defer func() { ss.Team().PermanentDelete(team.Id) }()
|
||||
|
||||
channel := &model.Channel{
|
||||
TeamId: team.Id,
|
||||
DisplayName: "test_share_flag",
|
||||
Name: "test_share_flag",
|
||||
Type: model.ChannelTypeOpen,
|
||||
}
|
||||
channelSaved, err := ss.Channel().Save(channel, 999)
|
||||
require.NoError(t, err)
|
||||
defer func() { ss.Channel().PermanentDelete(channelSaved.Id) }()
|
||||
|
||||
userID := model.NewId()
|
||||
_, err = ss.Post().Save(&model.Post{
|
||||
UserId: userID,
|
||||
ChannelId: channel.Id,
|
||||
Message: "test",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
dpc, err := ss.Channel().PostCountsByDuration([]string{channelSaved.Id}, 0, &userID, model.PostsByDay, time.Now().Location())
|
||||
require.NoError(t, err)
|
||||
require.Len(t, dpc, 1)
|
||||
require.Equal(t, channel.Id, dpc[0].ChannelID)
|
||||
require.Equal(t, 1, dpc[0].PostCount)
|
||||
}
|
||||
|
||||
@@ -11,6 +11,8 @@ import (
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
|
||||
store "github.com/mattermost/mattermost-server/v6/store"
|
||||
|
||||
time "time"
|
||||
)
|
||||
|
||||
// ChannelStore is an autogenerated mock type for the ChannelStore type
|
||||
@@ -266,13 +268,13 @@ func (_m *ChannelStore) CreateSidebarCategory(userID string, teamID string, newC
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Delete provides a mock function with given fields: channelID, time
|
||||
func (_m *ChannelStore) Delete(channelID string, time int64) error {
|
||||
ret := _m.Called(channelID, time)
|
||||
// Delete provides a mock function with given fields: channelID, timestamp
|
||||
func (_m *ChannelStore) Delete(channelID string, timestamp int64) error {
|
||||
ret := _m.Called(channelID, timestamp)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(string, int64) error); ok {
|
||||
r0 = rf(channelID, time)
|
||||
r0 = rf(channelID, timestamp)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
@@ -1717,6 +1719,29 @@ func (_m *ChannelStore) PermanentDeleteMembersByUser(userID string) error {
|
||||
return r0
|
||||
}
|
||||
|
||||
// PostCountsByDuration provides a mock function with given fields: channelIDs, sinceUnixMillis, userID, duration, groupingLocation
|
||||
func (_m *ChannelStore) PostCountsByDuration(channelIDs []string, sinceUnixMillis int64, userID *string, duration model.PostCountGrouping, groupingLocation *time.Location) ([]*model.DurationPostCount, error) {
|
||||
ret := _m.Called(channelIDs, sinceUnixMillis, userID, duration, groupingLocation)
|
||||
|
||||
var r0 []*model.DurationPostCount
|
||||
if rf, ok := ret.Get(0).(func([]string, int64, *string, model.PostCountGrouping, *time.Location) []*model.DurationPostCount); ok {
|
||||
r0 = rf(channelIDs, sinceUnixMillis, userID, duration, groupingLocation)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]*model.DurationPostCount)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func([]string, int64, *string, model.PostCountGrouping, *time.Location) error); ok {
|
||||
r1 = rf(channelIDs, sinceUnixMillis, userID, duration, groupingLocation)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// RemoveAllDeactivatedMembers provides a mock function with given fields: channelID
|
||||
func (_m *ChannelStore) RemoveAllDeactivatedMembers(channelID string) error {
|
||||
ret := _m.Called(channelID)
|
||||
@@ -1773,13 +1798,13 @@ func (_m *ChannelStore) ResetAllChannelSchemes() error {
|
||||
return r0
|
||||
}
|
||||
|
||||
// Restore provides a mock function with given fields: channelID, time
|
||||
func (_m *ChannelStore) Restore(channelID string, time int64) error {
|
||||
ret := _m.Called(channelID, time)
|
||||
// Restore provides a mock function with given fields: channelID, timestamp
|
||||
func (_m *ChannelStore) Restore(channelID string, timestamp int64) error {
|
||||
ret := _m.Called(channelID, timestamp)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(string, int64) error); ok {
|
||||
r0 = rf(channelID, time)
|
||||
r0 = rf(channelID, timestamp)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
@@ -35,13 +35,13 @@ func (_m *CommandStore) AnalyticsCommandCount(teamID string) (int64, error) {
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Delete provides a mock function with given fields: commandID, time
|
||||
func (_m *CommandStore) Delete(commandID string, time int64) error {
|
||||
ret := _m.Called(commandID, time)
|
||||
// Delete provides a mock function with given fields: commandID, timestamp
|
||||
func (_m *CommandStore) Delete(commandID string, timestamp int64) error {
|
||||
ret := _m.Called(commandID, timestamp)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(string, int64) error); ok {
|
||||
r0 = rf(commandID, time)
|
||||
r0 = rf(commandID, timestamp)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
@@ -16,13 +16,13 @@ type EmojiStore struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// Delete provides a mock function with given fields: emoji, time
|
||||
func (_m *EmojiStore) Delete(emoji *model.Emoji, time int64) error {
|
||||
ret := _m.Called(emoji, time)
|
||||
// Delete provides a mock function with given fields: emoji, timestamp
|
||||
func (_m *EmojiStore) Delete(emoji *model.Emoji, timestamp int64) error {
|
||||
ret := _m.Called(emoji, timestamp)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(*model.Emoji, int64) error); ok {
|
||||
r0 = rf(emoji, time)
|
||||
r0 = rf(emoji, timestamp)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
@@ -88,13 +88,13 @@ func (_m *PostStore) ClearCaches() {
|
||||
_m.Called()
|
||||
}
|
||||
|
||||
// Delete provides a mock function with given fields: postID, time, deleteByID
|
||||
func (_m *PostStore) Delete(postID string, time int64, deleteByID string) error {
|
||||
ret := _m.Called(postID, time, deleteByID)
|
||||
// Delete provides a mock function with given fields: postID, timestamp, deleteByID
|
||||
func (_m *PostStore) Delete(postID string, timestamp int64, deleteByID string) error {
|
||||
ret := _m.Called(postID, timestamp, deleteByID)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(string, int64, string) error); ok {
|
||||
r0 = rf(postID, time, deleteByID)
|
||||
r0 = rf(postID, timestamp, deleteByID)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
@@ -354,13 +354,13 @@ func (_m *PostStore) GetParentsForExportAfter(limit int, afterID string) ([]*mod
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetPostAfterTime provides a mock function with given fields: channelID, time, collapsedThreads
|
||||
func (_m *PostStore) GetPostAfterTime(channelID string, time int64, collapsedThreads bool) (*model.Post, error) {
|
||||
ret := _m.Called(channelID, time, collapsedThreads)
|
||||
// GetPostAfterTime provides a mock function with given fields: channelID, timestamp, collapsedThreads
|
||||
func (_m *PostStore) GetPostAfterTime(channelID string, timestamp int64, collapsedThreads bool) (*model.Post, error) {
|
||||
ret := _m.Called(channelID, timestamp, collapsedThreads)
|
||||
|
||||
var r0 *model.Post
|
||||
if rf, ok := ret.Get(0).(func(string, int64, bool) *model.Post); ok {
|
||||
r0 = rf(channelID, time, collapsedThreads)
|
||||
r0 = rf(channelID, timestamp, collapsedThreads)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*model.Post)
|
||||
@@ -369,7 +369,7 @@ func (_m *PostStore) GetPostAfterTime(channelID string, time int64, collapsedThr
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(string, int64, bool) error); ok {
|
||||
r1 = rf(channelID, time, collapsedThreads)
|
||||
r1 = rf(channelID, timestamp, collapsedThreads)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
@@ -377,20 +377,20 @@ func (_m *PostStore) GetPostAfterTime(channelID string, time int64, collapsedThr
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetPostIdAfterTime provides a mock function with given fields: channelID, time, collapsedThreads
|
||||
func (_m *PostStore) GetPostIdAfterTime(channelID string, time int64, collapsedThreads bool) (string, error) {
|
||||
ret := _m.Called(channelID, time, collapsedThreads)
|
||||
// GetPostIdAfterTime provides a mock function with given fields: channelID, timestamp, collapsedThreads
|
||||
func (_m *PostStore) GetPostIdAfterTime(channelID string, timestamp int64, collapsedThreads bool) (string, error) {
|
||||
ret := _m.Called(channelID, timestamp, collapsedThreads)
|
||||
|
||||
var r0 string
|
||||
if rf, ok := ret.Get(0).(func(string, int64, bool) string); ok {
|
||||
r0 = rf(channelID, time, collapsedThreads)
|
||||
r0 = rf(channelID, timestamp, collapsedThreads)
|
||||
} else {
|
||||
r0 = ret.Get(0).(string)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(string, int64, bool) error); ok {
|
||||
r1 = rf(channelID, time, collapsedThreads)
|
||||
r1 = rf(channelID, timestamp, collapsedThreads)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
@@ -398,20 +398,20 @@ func (_m *PostStore) GetPostIdAfterTime(channelID string, time int64, collapsedT
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetPostIdBeforeTime provides a mock function with given fields: channelID, time, collapsedThreads
|
||||
func (_m *PostStore) GetPostIdBeforeTime(channelID string, time int64, collapsedThreads bool) (string, error) {
|
||||
ret := _m.Called(channelID, time, collapsedThreads)
|
||||
// GetPostIdBeforeTime provides a mock function with given fields: channelID, timestamp, collapsedThreads
|
||||
func (_m *PostStore) GetPostIdBeforeTime(channelID string, timestamp int64, collapsedThreads bool) (string, error) {
|
||||
ret := _m.Called(channelID, timestamp, collapsedThreads)
|
||||
|
||||
var r0 string
|
||||
if rf, ok := ret.Get(0).(func(string, int64, bool) string); ok {
|
||||
r0 = rf(channelID, time, collapsedThreads)
|
||||
r0 = rf(channelID, timestamp, collapsedThreads)
|
||||
} else {
|
||||
r0 = ret.Get(0).(string)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(string, int64, bool) error); ok {
|
||||
r1 = rf(channelID, time, collapsedThreads)
|
||||
r1 = rf(channelID, timestamp, collapsedThreads)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
@@ -534,13 +534,13 @@ func (_m *PostStore) GetPostsByIds(postIds []string) ([]*model.Post, error) {
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetPostsCreatedAt provides a mock function with given fields: channelID, time
|
||||
func (_m *PostStore) GetPostsCreatedAt(channelID string, time int64) ([]*model.Post, error) {
|
||||
ret := _m.Called(channelID, time)
|
||||
// GetPostsCreatedAt provides a mock function with given fields: channelID, timestamp
|
||||
func (_m *PostStore) GetPostsCreatedAt(channelID string, timestamp int64) ([]*model.Post, error) {
|
||||
ret := _m.Called(channelID, timestamp)
|
||||
|
||||
var r0 []*model.Post
|
||||
if rf, ok := ret.Get(0).(func(string, int64) []*model.Post); ok {
|
||||
r0 = rf(channelID, time)
|
||||
r0 = rf(channelID, timestamp)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]*model.Post)
|
||||
@@ -549,7 +549,7 @@ func (_m *PostStore) GetPostsCreatedAt(channelID string, time int64) ([]*model.P
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(string, int64) error); ok {
|
||||
r1 = rf(channelID, time)
|
||||
r1 = rf(channelID, timestamp)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
@@ -264,13 +264,13 @@ func (_m *SessionStore) UpdateExpiredNotify(sessionid string, notified bool) err
|
||||
return r0
|
||||
}
|
||||
|
||||
// UpdateExpiresAt provides a mock function with given fields: sessionID, time
|
||||
func (_m *SessionStore) UpdateExpiresAt(sessionID string, time int64) error {
|
||||
ret := _m.Called(sessionID, time)
|
||||
// UpdateExpiresAt provides a mock function with given fields: sessionID, timestamp
|
||||
func (_m *SessionStore) UpdateExpiresAt(sessionID string, timestamp int64) error {
|
||||
ret := _m.Called(sessionID, timestamp)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(string, int64) error); ok {
|
||||
r0 = rf(sessionID, time)
|
||||
r0 = rf(sessionID, timestamp)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
@@ -278,13 +278,13 @@ func (_m *SessionStore) UpdateExpiresAt(sessionID string, time int64) error {
|
||||
return r0
|
||||
}
|
||||
|
||||
// UpdateLastActivityAt provides a mock function with given fields: sessionID, time
|
||||
func (_m *SessionStore) UpdateLastActivityAt(sessionID string, time int64) error {
|
||||
ret := _m.Called(sessionID, time)
|
||||
// UpdateLastActivityAt provides a mock function with given fields: sessionID, timestamp
|
||||
func (_m *SessionStore) UpdateLastActivityAt(sessionID string, timestamp int64) error {
|
||||
ret := _m.Called(sessionID, timestamp)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(string, int64) error); ok {
|
||||
r0 = rf(sessionID, time)
|
||||
r0 = rf(sessionID, timestamp)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
@@ -18,20 +18,20 @@ type UserStore struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// AnalyticsActiveCount provides a mock function with given fields: time, options
|
||||
func (_m *UserStore) AnalyticsActiveCount(time int64, options model.UserCountOptions) (int64, error) {
|
||||
ret := _m.Called(time, options)
|
||||
// AnalyticsActiveCount provides a mock function with given fields: timestamp, options
|
||||
func (_m *UserStore) AnalyticsActiveCount(timestamp int64, options model.UserCountOptions) (int64, error) {
|
||||
ret := _m.Called(timestamp, options)
|
||||
|
||||
var r0 int64
|
||||
if rf, ok := ret.Get(0).(func(int64, model.UserCountOptions) int64); ok {
|
||||
r0 = rf(time, options)
|
||||
r0 = rf(timestamp, options)
|
||||
} else {
|
||||
r0 = ret.Get(0).(int64)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(int64, model.UserCountOptions) error); ok {
|
||||
r1 = rf(time, options)
|
||||
r1 = rf(timestamp, options)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
@@ -61,13 +61,13 @@ func (_m *WebhookStore) ClearCaches() {
|
||||
_m.Called()
|
||||
}
|
||||
|
||||
// DeleteIncoming provides a mock function with given fields: webhookID, time
|
||||
func (_m *WebhookStore) DeleteIncoming(webhookID string, time int64) error {
|
||||
ret := _m.Called(webhookID, time)
|
||||
// DeleteIncoming provides a mock function with given fields: webhookID, timestamp
|
||||
func (_m *WebhookStore) DeleteIncoming(webhookID string, timestamp int64) error {
|
||||
ret := _m.Called(webhookID, timestamp)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(string, int64) error); ok {
|
||||
r0 = rf(webhookID, time)
|
||||
r0 = rf(webhookID, timestamp)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
@@ -75,13 +75,13 @@ func (_m *WebhookStore) DeleteIncoming(webhookID string, time int64) error {
|
||||
return r0
|
||||
}
|
||||
|
||||
// DeleteOutgoing provides a mock function with given fields: webhookID, time
|
||||
func (_m *WebhookStore) DeleteOutgoing(webhookID string, time int64) error {
|
||||
ret := _m.Called(webhookID, time)
|
||||
// DeleteOutgoing provides a mock function with given fields: webhookID, timestamp
|
||||
func (_m *WebhookStore) DeleteOutgoing(webhookID string, timestamp int64) error {
|
||||
ret := _m.Called(webhookID, timestamp)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(string, int64) error); ok {
|
||||
r0 = rf(webhookID, time)
|
||||
r0 = rf(webhookID, timestamp)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ func TestPostStore(t *testing.T, ss store.Store, s SqlStore) {
|
||||
t.Run("GetPosts", func(t *testing.T) { testPostStoreGetPosts(t, ss) })
|
||||
t.Run("GetPostBeforeAfter", func(t *testing.T) { testPostStoreGetPostBeforeAfter(t, ss) })
|
||||
t.Run("UserCountsWithPostsByDay", func(t *testing.T) { testUserCountsWithPostsByDay(t, ss) })
|
||||
t.Run("PostCountsByDay", func(t *testing.T) { testPostCountsByDay(t, ss) })
|
||||
t.Run("PostCountsByDuration", func(t *testing.T) { testPostCountsByDay(t, ss) })
|
||||
t.Run("GetFlaggedPostsForTeam", func(t *testing.T) { testPostStoreGetFlaggedPostsForTeam(t, ss, s) })
|
||||
t.Run("GetFlaggedPosts", func(t *testing.T) { testPostStoreGetFlaggedPosts(t, ss) })
|
||||
t.Run("GetFlaggedPostsForChannel", func(t *testing.T) { testPostStoreGetFlaggedPostsForChannel(t, ss) })
|
||||
|
||||
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Ссылка в новой задаче
Block a user