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>
Этот коммит содержится в:
Martin Kraft
2022-06-13 16:22:34 -04:00
коммит произвёл GitHub
родитель c03eb778c8
Коммит 182ae1234a
29 изменённых файлов: 2055 добавлений и 1533 удалений

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

@@ -209,3 +209,24 @@ func requireLicense(f handlerFunc) handlerFunc {
f(c, w, r) 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 ( import (
"encoding/json" "encoding/json"
"net/http" "net/http"
"time"
"github.com/mattermost/mattermost-server/v6/app"
"github.com/mattermost/mattermost-server/v6/model" "github.com/mattermost/mattermost-server/v6/model"
) )
func (api *API) InitInsights() { func (api *API) InitInsights() {
// Reactions // Reactions
api.BaseRoutes.InsightsForTeam.Handle("/reactions", api.APISessionRequired(getTopReactionsForTeamSince)).Methods("GET") api.BaseRoutes.InsightsForTeam.Handle("/reactions", api.APISessionRequired(minimumProfessionalLicense(rejectGuests(getTopReactionsForTeamSince)))).Methods("GET")
api.BaseRoutes.InsightsForUser.Handle("/reactions", api.APISessionRequired(getTopReactionsForUserSince)).Methods("GET") api.BaseRoutes.InsightsForUser.Handle("/reactions", api.APISessionRequired(minimumProfessionalLicense(rejectGuests(getTopReactionsForUserSince)))).Methods("GET")
// Channels // Channels
api.BaseRoutes.InsightsForTeam.Handle("/channels", api.APISessionRequired(getTopChannelsForTeamSince)).Methods("GET") api.BaseRoutes.InsightsForTeam.Handle("/channels", api.APISessionRequired(minimumProfessionalLicense(rejectGuests(getTopChannelsForTeamSince)))).Methods("GET")
api.BaseRoutes.InsightsForUser.Handle("/channels", api.APISessionRequired(getTopChannelsForUserSince)).Methods("GET") api.BaseRoutes.InsightsForUser.Handle("/channels", api.APISessionRequired(minimumProfessionalLicense(rejectGuests(getTopChannelsForUserSince)))).Methods("GET")
} }
// Top Reactions // Top Reactions
@@ -39,14 +41,16 @@ func getTopReactionsForTeamSince(c *Context, w http.ResponseWriter, r *http.Requ
return return
} }
startTime, err := model.GetStartUnixMilliForTimeRange(c.Params.TimeRange) user, err := c.App.GetUser(c.AppContext.Session().UserId)
if err != nil { if err != nil {
c.Err = err c.Err = err
return return
} }
startTime := model.StartOfDayForTimeRange(c.Params.TimeRange, user.GetTimezoneLocation())
topReactionList, err := c.App.GetTopReactionsForTeamSince(c.Params.TeamId, c.AppContext.Session().UserId, &model.InsightsOpts{ topReactionList, err := c.App.GetTopReactionsForTeamSince(c.Params.TeamId, c.AppContext.Session().UserId, &model.InsightsOpts{
StartUnixMilli: startTime, StartUnixMilli: startTime.UnixMilli(),
Page: c.Params.Page, Page: c.Params.Page,
PerPage: c.Params.PerPage, 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 { if err != nil {
c.Err = err c.Err = err
return return
} }
startTime := model.StartOfDayForTimeRange(c.Params.TimeRange, user.GetTimezoneLocation())
topReactionList, err := c.App.GetTopReactionsForUserSince(c.AppContext.Session().UserId, c.Params.TeamId, &model.InsightsOpts{ topReactionList, err := c.App.GetTopReactionsForUserSince(c.AppContext.Session().UserId, c.Params.TeamId, &model.InsightsOpts{
StartUnixMilli: startTime, StartUnixMilli: startTime.UnixMilli(),
Page: c.Params.Page, Page: c.Params.Page,
PerPage: c.Params.PerPage, PerPage: c.Params.PerPage,
}) })
@@ -130,14 +136,17 @@ func getTopChannelsForTeamSince(c *Context, w http.ResponseWriter, r *http.Reque
return return
} }
startTime, err := model.GetStartUnixMilliForTimeRange(c.Params.TimeRange) user, err := c.App.GetUser(c.AppContext.Session().UserId)
if err != nil { if err != nil {
c.Err = err c.Err = err
return 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{ topChannels, err := c.App.GetTopChannelsForTeamSince(c.Params.TeamId, c.AppContext.Session().UserId, &model.InsightsOpts{
StartUnixMilli: startTime, StartUnixMilli: startTime.UnixMilli(),
Page: c.Params.Page, Page: c.Params.Page,
PerPage: c.Params.PerPage, PerPage: c.Params.PerPage,
}) })
@@ -146,6 +155,12 @@ func getTopChannelsForTeamSince(c *Context, w http.ResponseWriter, r *http.Reque
return 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) js, jsonErr := json.Marshal(topChannels)
if jsonErr != nil { if jsonErr != nil {
c.Err = model.NewAppError("getTopChannelsForTeamSince", "api.marshal_error", nil, jsonErr.Error(), http.StatusInternalServerError) 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 { if err != nil {
c.Err = err c.Err = err
return 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{ topChannels, err := c.App.GetTopChannelsForUserSince(c.AppContext.Session().UserId, c.Params.TeamId, &model.InsightsOpts{
StartUnixMilli: startTime, StartUnixMilli: startTime.UnixMilli(),
Page: c.Params.Page, Page: c.Params.Page,
PerPage: c.Params.PerPage, PerPage: c.Params.PerPage,
}) })
@@ -194,6 +212,12 @@ func getTopChannelsForUserSince(c *Context, w http.ResponseWriter, r *http.Reque
return 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) js, jsonErr := json.Marshal(topChannels)
if jsonErr != nil { if jsonErr != nil {
c.Err = model.NewAppError("getTopChannelsForUserSince", "api.marshal_error", nil, jsonErr.Error(), http.StatusInternalServerError) 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) 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) th.ConfigStore.SetReadOnlyFF(false)
defer th.ConfigStore.SetReadOnlyFF(true) defer th.ConfigStore.SetReadOnlyFF(true)
th.App.UpdateConfig(func(cfg *model.Config) { cfg.FeatureFlags.InsightsEnabled = true }) th.App.UpdateConfig(func(cfg *model.Config) { cfg.FeatureFlags.InsightsEnabled = true })
th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuProfessional))
client := th.Client client := th.Client
@@ -246,6 +247,7 @@ func TestGetTopReactionsForUserSince(t *testing.T) {
th.ConfigStore.SetReadOnlyFF(false) th.ConfigStore.SetReadOnlyFF(false)
defer th.ConfigStore.SetReadOnlyFF(true) defer th.ConfigStore.SetReadOnlyFF(true)
th.App.UpdateConfig(func(cfg *model.Config) { cfg.FeatureFlags.InsightsEnabled = true }) th.App.UpdateConfig(func(cfg *model.Config) { cfg.FeatureFlags.InsightsEnabled = true })
th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuProfessional))
client := th.Client client := th.Client
@@ -437,6 +439,7 @@ func TestGetTopChannelsForTeamSince(t *testing.T) {
th.ConfigStore.SetReadOnlyFF(false) th.ConfigStore.SetReadOnlyFF(false)
defer th.ConfigStore.SetReadOnlyFF(true) defer th.ConfigStore.SetReadOnlyFF(true)
th.App.UpdateConfig(func(cfg *model.Config) { cfg.FeatureFlags.InsightsEnabled = true }) th.App.UpdateConfig(func(cfg *model.Config) { cfg.FeatureFlags.InsightsEnabled = true })
th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuProfessional))
client := th.Client client := th.Client
userId := th.BasicUser.Id userId := th.BasicUser.Id
@@ -485,6 +488,10 @@ func TestGetTopChannelsForTeamSince(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, channel6.Id, topChannels.Items[0].ID) assert.Equal(t, channel6.Id, topChannels.Items[0].ID)
assert.Equal(t, int64(1), topChannels.Items[0].MessageCount) 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) { 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) th.ConfigStore.SetReadOnlyFF(false)
defer th.ConfigStore.SetReadOnlyFF(true) defer th.ConfigStore.SetReadOnlyFF(true)
th.App.UpdateConfig(func(cfg *model.Config) { cfg.FeatureFlags.InsightsEnabled = true }) th.App.UpdateConfig(func(cfg *model.Config) { cfg.FeatureFlags.InsightsEnabled = true })
th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuProfessional))
client := th.Client client := th.Client
userId := th.BasicUser.Id userId := th.BasicUser.Id
@@ -579,6 +587,10 @@ func TestGetTopChannelsForUserSince(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, channel6.Id, topChannels.Items[0].ID) assert.Equal(t, channel6.Id, topChannels.Items[0].ID)
assert.Equal(t, int64(1), topChannels.Items[0].MessageCount) 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) { 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, // PopulateWebConnConfig checks if the connection id already exists in the hub,
// and if so, accordingly populates the other fields of the webconn. // and if so, accordingly populates the other fields of the webconn.
PopulateWebConnConfig(s *model.Session, cfg *WebConnConfig, seqVal string) (*WebConnConfig, error) 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 // PromoteGuestToUser Convert user's roles and all his membership's roles from
// guest roles to regular user roles. // guest roles to regular user roles.
PromoteGuestToUser(c *request.Context, user *model.User, requestorId string) *model.AppError PromoteGuestToUser(c *request.Context, user *model.User, requestorId string) *model.AppError

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

@@ -10,6 +10,7 @@ import (
"fmt" "fmt"
"net/http" "net/http"
"strings" "strings"
"time"
"github.com/mattermost/mattermost-server/v6/app/request" "github.com/mattermost/mattermost-server/v6/app/request"
"github.com/mattermost/mattermost-server/v6/model" "github.com/mattermost/mattermost-server/v6/model"
@@ -3417,3 +3418,19 @@ func (a *App) GetTopChannelsForUserSince(userID, teamID string, opts *model.Insi
} }
return topChannels, nil 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" "strings"
"sync" "sync"
"testing" "testing"
"time"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock" "github.com/stretchr/testify/mock"
@@ -2418,10 +2419,10 @@ func TestGetTopChannelsForTeamSince(t *testing.T) {
{ID: channel5.Id, MessageCount: 2}, {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) { 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) require.Nil(t, err)
for i, channel := range topChannels.Items { for i, channel := range topChannels.Items {
@@ -2429,7 +2430,7 @@ func TestGetTopChannelsForTeamSince(t *testing.T) {
assert.Equal(t, expectedTopChannels[i].MessageCount, channel.MessageCount) 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) require.Nil(t, err)
assert.Equal(t, channel6.Id, topChannels.Items[0].ID) assert.Equal(t, channel6.Id, topChannels.Items[0].ID)
assert.Equal(t, int64(1), topChannels.Items[0].MessageCount) assert.Equal(t, int64(1), topChannels.Items[0].MessageCount)
@@ -2476,10 +2477,10 @@ func TestGetTopChannelsForUserSince(t *testing.T) {
{ID: channel5.Id, MessageCount: 2}, {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) { 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) require.Nil(t, err)
for i, channel := range topChannels.Items { for i, channel := range topChannels.Items {
@@ -2487,9 +2488,132 @@ func TestGetTopChannelsForUserSince(t *testing.T) {
assert.Equal(t, expectedTopChannels[i].MessageCount, channel.MessageCount) 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) require.Nil(t, err)
assert.Equal(t, channel6.Id, topChannels.Items[0].ID) assert.Equal(t, channel6.Id, topChannels.Items[0].ID)
assert.Equal(t, int64(1), topChannels.Items[0].MessageCount) 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 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 { func (a *OpenTracingAppLayer) PostPatchWithProxyRemovedFromImageURLs(patch *model.PostPatch) *model.PostPatch {
origCtx := a.ctx origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.PostPatchWithProxyRemovedFromImageURLs") 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[3] = &model.TopReaction{EmojiName: "sad", Count: int64(3)}
expectedTopReactions[4] = &model.TopReaction{EmojiName: "happy", Count: int64(2)} 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) { 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) require.Nil(t, err)
reactions := topReactions.Items 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].EmojiName, reaction.EmojiName)
assert.Equal(t, expectedTopReactions[i].Count, reaction.Count) 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) require.Nil(t, err)
reactions = topReactions.Items 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) { 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 }) 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) assert.NotNil(t, err)
}) })
} }
@@ -402,10 +402,10 @@ func TestGetTopReactionsForUserSince(t *testing.T) {
expectedTopReactions[3] = &model.TopReaction{EmojiName: "heart", Count: int64(3)} expectedTopReactions[3] = &model.TopReaction{EmojiName: "heart", Count: int64(3)}
expectedTopReactions[4] = &model.TopReaction{EmojiName: "blush", Count: int64(2)} 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) { 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) require.Nil(t, err)
reactions := topReactions.Items reactions := topReactions.Items
@@ -414,7 +414,7 @@ func TestGetTopReactionsForUserSince(t *testing.T) {
assert.Equal(t, expectedTopReactions[i].Count, reaction.Count) 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) require.Nil(t, err)
reactions = topReactions.Items reactions = topReactions.Items
assert.Equal(t, "100", reactions[0].EmojiName) 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) { 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 }) 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) assert.NotNil(t, err)
}) })
} }

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

@@ -187,6 +187,10 @@
"id": "api.admin.upload_brand_image.too_large.app_error", "id": "api.admin.upload_brand_image.too_large.app_error",
"translation": "Unable to upload file. File is too large." "translation": "Unable to upload file. File is too large."
}, },
{
"id": "api.authorization_error.guest",
"translation": " "
},
{ {
"id": "api.back_to_app", "id": "api.back_to_app",
"translation": "Back to {{.SiteName}}" "translation": "Back to {{.SiteName}}"
@@ -2053,6 +2057,10 @@
"id": "api.license_error", "id": "api.license_error",
"translation": "api endpoint requires a license" "translation": "api endpoint requires a license"
}, },
{
"id": "api.license_error.professional_or_enterprise",
"translation": " "
},
{ {
"id": "api.marshal_error", "id": "api.marshal_error",
"translation": "Failed to marshal." "translation": "Failed to marshal."
@@ -4531,6 +4539,10 @@
"id": "app.channel.get_pinnedpost_count.app_error", "id": "app.channel.get_pinnedpost_count.app_error",
"translation": "Unable to get the channel pinned post count." "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", "id": "app.channel.get_private_channels.get.app_error",
"translation": "Unable to get private channels." "translation": "Unable to get private channels."
@@ -8531,10 +8543,6 @@
"id": "model.incoming_hook.username.app_error", "id": "model.incoming_hook.username.app_error",
"translation": "Invalid username." "translation": "Invalid username."
}, },
{
"id": "model.insights.time_range.app_error",
"translation": " "
},
{ {
"id": "model.job.is_valid.create_at.app_error", "id": "model.job.is_valid.create_at.app_error",
"translation": "Create at must be a valid time." "translation": "Create at must be a valid time."

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

@@ -4,14 +4,18 @@
package model package model
import ( import (
"net/http"
"time" "time"
) )
type PostCountGrouping string
const ( const (
TimeRangeToday string = "today" TimeRangeToday string = "today"
TimeRange7Day string = "7_day" TimeRange7Day string = "7_day"
TimeRange28Day string = "28_day" TimeRange28Day string = "28_day"
PostsByHour PostCountGrouping = "hour"
PostsByDay PostCountGrouping = "day"
) )
type InsightsOpts struct { type InsightsOpts struct {
@@ -38,7 +42,16 @@ type TopReaction struct {
// Top Channels // Top Channels
type TopChannelList struct { type TopChannelList struct {
InsightsListData 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 { type TopChannel struct {
@@ -50,21 +63,116 @@ type TopChannel struct {
MessageCount int64 `json:"message_count"` MessageCount int64 `json:"message_count"`
} }
// GetStartUnixMilliForTimeRange gets the unix start time in milliseconds from the given time range. type DurationPostCount struct {
// Time range can be one of: "1_day", "7_day", or "28_day". ChannelID string `db:"channelid"`
func GetStartUnixMilliForTimeRange(timeRange string) (int64, *AppError) { // Duration is an ISO8601 date string representing either a day or a day and hour (ex. "2022-05-26" or "2022-05-26T14").
now := time.Now() Duration string `db:"duration"`
_, offset := now.Zone() PostCount int `db:"postcount"`
}
func TimeRangeToNumberDays(timeRange string) int {
var n int
switch timeRange { switch timeRange {
case TimeRangeToday: case TimeRangeToday:
return GetStartOfDayMillis(now, offset), nil n = 1
case TimeRange7Day: case TimeRange7Day:
return GetStartOfDayMillis(now.Add(time.Hour*time.Duration(-168)), offset), nil n = 7
case TimeRange28Day: 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 // 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" "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) { func TestGetTopReactionListWithPagination(t *testing.T) {
reactions := []*TopReaction{ reactions := []*TopReaction{
{EmojiName: "smile", Count: 200}, {EmojiName: "smile", Count: 200},

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

@@ -11,6 +11,7 @@ import (
"regexp" "regexp"
"sort" "sort"
"strings" "strings"
"time"
"unicode/utf8" "unicode/utf8"
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
@@ -782,6 +783,14 @@ func (u *User) GetPreferredTimezone() string {
return GetPreferredTimezone(u.Timezone) 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). // IsRemote returns true if the user belongs to a remote cluster (has RemoteId).
func (u *User) IsRemote() bool { func (u *User) IsRemote() bool {
return u.RemoteId != nil && *u.RemoteId != "" return u.RemoteId != nil && *u.RemoteId != ""

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

@@ -8,6 +8,7 @@ package opentracinglayer
import ( import (
"context" "context"
"time"
"github.com/mattermost/mattermost-server/v6/model" "github.com/mattermost/mattermost-server/v6/model"
"github.com/mattermost/mattermost-server/v6/services/tracing" "github.com/mattermost/mattermost-server/v6/services/tracing"

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

@@ -9,6 +9,7 @@ package retrylayer
import ( import (
"context" "context"
timepkg "time" timepkg "time"
"time"
"github.com/lib/pq" "github.com/lib/pq"
"github.com/mattermost/mattermost-server/v6/model" "github.com/mattermost/mattermost-server/v6/model"

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

@@ -8,7 +8,7 @@ package timerlayer
import ( import (
"context" "context"
timemodule "time" "time"
"github.com/mattermost/mattermost-server/v6/einterfaces" "github.com/mattermost/mattermost-server/v6/einterfaces"
"github.com/mattermost/mattermost-server/v6/model" "github.com/mattermost/mattermost-server/v6/model"
@@ -38,13 +38,13 @@ type {{.Name}} struct {
{{range $substoreName, $substore := .SubStores}} {{range $substoreName, $substore := .SubStores}}
{{range $index, $element := $substore.Methods}} {{range $index, $element := $substore.Methods}}
func (s *{{$.Name}}{{$substoreName}}Store) {{$index}}({{$element.Params | joinParamsWithType}}) {{$element.Results | joinResultsForSignature}} { func (s *{{$.Name}}{{$substoreName}}Store) {{$index}}({{$element.Params | joinParamsWithType}}) {{$element.Results | joinResultsForSignature}} {
start := timemodule.Now() start := time.Now()
{{if $element.Results | len | eq 0}} {{if $element.Results | len | eq 0}}
s.{{$substoreName}}Store.{{$index}}({{$element.Params | joinParams}}) s.{{$substoreName}}Store.{{$index}}({{$element.Params | joinParams}})
{{else}} {{else}}
{{genResultsVars $element.Results false }} := s.{{$substoreName}}Store.{{$index}}({{$element.Params | joinParams}}) {{genResultsVars $element.Results false }} := s.{{$substoreName}}Store.{{$index}}({{$element.Params | joinParams}})
{{end}} {{end}}
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second) elapsed := float64(time.Since(start)) / float64(time.Second)
if s.Root.Metrics != nil { if s.Root.Metrics != nil {
success := "false" success := "false"
if {{$element.Results | errorToBoolean}} { if {{$element.Results | errorToBoolean}} {

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

@@ -8,6 +8,7 @@ package opentracinglayer
import ( import (
"context" "context"
"time"
"github.com/mattermost/mattermost-server/v6/model" "github.com/mattermost/mattermost-server/v6/model"
"github.com/mattermost/mattermost-server/v6/services/tracing" "github.com/mattermost/mattermost-server/v6/services/tracing"
@@ -745,7 +746,7 @@ func (s *OpenTracingLayerChannelStore) CreateSidebarCategory(userID string, team
return result, err 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() origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.Delete") span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.Delete")
s.Root.Store.SetContext(newCtx) s.Root.Store.SetContext(newCtx)
@@ -754,7 +755,7 @@ func (s *OpenTracingLayerChannelStore) Delete(channelID string, time int64) erro
}() }()
defer span.Finish() defer span.Finish()
err := s.ChannelStore.Delete(channelID, time) err := s.ChannelStore.Delete(channelID, timestamp)
if err != nil { if err != nil {
span.LogFields(spanlog.Error(err)) span.LogFields(spanlog.Error(err))
ext.Error.Set(span, true) ext.Error.Set(span, true)
@@ -2014,6 +2015,24 @@ func (s *OpenTracingLayerChannelStore) PermanentDeleteMembersByUser(userID strin
return err 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 { func (s *OpenTracingLayerChannelStore) RemoveAllDeactivatedMembers(channelID string) error {
origCtx := s.Root.Store.Context() origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.RemoveAllDeactivatedMembers") span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.RemoveAllDeactivatedMembers")
@@ -2086,7 +2105,7 @@ func (s *OpenTracingLayerChannelStore) ResetAllChannelSchemes() error {
return err 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() origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.Restore") span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.Restore")
s.Root.Store.SetContext(newCtx) s.Root.Store.SetContext(newCtx)
@@ -2095,7 +2114,7 @@ func (s *OpenTracingLayerChannelStore) Restore(channelID string, time int64) err
}() }()
defer span.Finish() defer span.Finish()
err := s.ChannelStore.Restore(channelID, time) err := s.ChannelStore.Restore(channelID, timestamp)
if err != nil { if err != nil {
span.LogFields(spanlog.Error(err)) span.LogFields(spanlog.Error(err))
ext.Error.Set(span, true) ext.Error.Set(span, true)
@@ -2788,7 +2807,7 @@ func (s *OpenTracingLayerCommandStore) AnalyticsCommandCount(teamID string) (int
return result, err 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() origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "CommandStore.Delete") span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "CommandStore.Delete")
s.Root.Store.SetContext(newCtx) s.Root.Store.SetContext(newCtx)
@@ -2797,7 +2816,7 @@ func (s *OpenTracingLayerCommandStore) Delete(commandID string, time int64) erro
}() }()
defer span.Finish() defer span.Finish()
err := s.CommandStore.Delete(commandID, time) err := s.CommandStore.Delete(commandID, timestamp)
if err != nil { if err != nil {
span.LogFields(spanlog.Error(err)) span.LogFields(spanlog.Error(err))
ext.Error.Set(span, true) ext.Error.Set(span, true)
@@ -3107,7 +3126,7 @@ func (s *OpenTracingLayerComplianceStore) Update(compliance *model.Compliance) (
return result, err 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() origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "EmojiStore.Delete") span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "EmojiStore.Delete")
s.Root.Store.SetContext(newCtx) s.Root.Store.SetContext(newCtx)
@@ -3116,7 +3135,7 @@ func (s *OpenTracingLayerEmojiStore) Delete(emoji *model.Emoji, time int64) erro
}() }()
defer span.Finish() defer span.Finish()
err := s.EmojiStore.Delete(emoji, time) err := s.EmojiStore.Delete(emoji, timestamp)
if err != nil { if err != nil {
span.LogFields(spanlog.Error(err)) span.LogFields(spanlog.Error(err))
ext.Error.Set(span, true) 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() origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "PostStore.Delete") span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "PostStore.Delete")
s.Root.Store.SetContext(newCtx) s.Root.Store.SetContext(newCtx)
@@ -5459,7 +5478,7 @@ func (s *OpenTracingLayerPostStore) Delete(postID string, time int64, deleteByID
}() }()
defer span.Finish() defer span.Finish()
err := s.PostStore.Delete(postID, time, deleteByID) err := s.PostStore.Delete(postID, timestamp, deleteByID)
if err != nil { if err != nil {
span.LogFields(spanlog.Error(err)) span.LogFields(spanlog.Error(err))
ext.Error.Set(span, true) ext.Error.Set(span, true)
@@ -5682,7 +5701,7 @@ func (s *OpenTracingLayerPostStore) GetParentsForExportAfter(limit int, afterID
return result, err 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() origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "PostStore.GetPostAfterTime") span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "PostStore.GetPostAfterTime")
s.Root.Store.SetContext(newCtx) s.Root.Store.SetContext(newCtx)
@@ -5691,7 +5710,7 @@ func (s *OpenTracingLayerPostStore) GetPostAfterTime(channelID string, time int6
}() }()
defer span.Finish() defer span.Finish()
result, err := s.PostStore.GetPostAfterTime(channelID, time, collapsedThreads) result, err := s.PostStore.GetPostAfterTime(channelID, timestamp, collapsedThreads)
if err != nil { if err != nil {
span.LogFields(spanlog.Error(err)) span.LogFields(spanlog.Error(err))
ext.Error.Set(span, true) ext.Error.Set(span, true)
@@ -5700,7 +5719,7 @@ func (s *OpenTracingLayerPostStore) GetPostAfterTime(channelID string, time int6
return result, err 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() origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "PostStore.GetPostIdAfterTime") span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "PostStore.GetPostIdAfterTime")
s.Root.Store.SetContext(newCtx) s.Root.Store.SetContext(newCtx)
@@ -5709,7 +5728,7 @@ func (s *OpenTracingLayerPostStore) GetPostIdAfterTime(channelID string, time in
}() }()
defer span.Finish() defer span.Finish()
result, err := s.PostStore.GetPostIdAfterTime(channelID, time, collapsedThreads) result, err := s.PostStore.GetPostIdAfterTime(channelID, timestamp, collapsedThreads)
if err != nil { if err != nil {
span.LogFields(spanlog.Error(err)) span.LogFields(spanlog.Error(err))
ext.Error.Set(span, true) ext.Error.Set(span, true)
@@ -5718,7 +5737,7 @@ func (s *OpenTracingLayerPostStore) GetPostIdAfterTime(channelID string, time in
return result, err 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() origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "PostStore.GetPostIdBeforeTime") span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "PostStore.GetPostIdBeforeTime")
s.Root.Store.SetContext(newCtx) s.Root.Store.SetContext(newCtx)
@@ -5727,7 +5746,7 @@ func (s *OpenTracingLayerPostStore) GetPostIdBeforeTime(channelID string, time i
}() }()
defer span.Finish() defer span.Finish()
result, err := s.PostStore.GetPostIdBeforeTime(channelID, time, collapsedThreads) result, err := s.PostStore.GetPostIdBeforeTime(channelID, timestamp, collapsedThreads)
if err != nil { if err != nil {
span.LogFields(spanlog.Error(err)) span.LogFields(spanlog.Error(err))
ext.Error.Set(span, true) ext.Error.Set(span, true)
@@ -5826,7 +5845,7 @@ func (s *OpenTracingLayerPostStore) GetPostsByIds(postIds []string) ([]*model.Po
return result, err 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() origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "PostStore.GetPostsCreatedAt") span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "PostStore.GetPostsCreatedAt")
s.Root.Store.SetContext(newCtx) s.Root.Store.SetContext(newCtx)
@@ -5835,7 +5854,7 @@ func (s *OpenTracingLayerPostStore) GetPostsCreatedAt(channelID string, time int
}() }()
defer span.Finish() defer span.Finish()
result, err := s.PostStore.GetPostsCreatedAt(channelID, time) result, err := s.PostStore.GetPostsCreatedAt(channelID, timestamp)
if err != nil { if err != nil {
span.LogFields(spanlog.Error(err)) span.LogFields(spanlog.Error(err))
ext.Error.Set(span, true) ext.Error.Set(span, true)
@@ -7639,7 +7658,7 @@ func (s *OpenTracingLayerSessionStore) UpdateExpiredNotify(sessionid string, not
return err 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() origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "SessionStore.UpdateExpiresAt") span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "SessionStore.UpdateExpiresAt")
s.Root.Store.SetContext(newCtx) s.Root.Store.SetContext(newCtx)
@@ -7648,7 +7667,7 @@ func (s *OpenTracingLayerSessionStore) UpdateExpiresAt(sessionID string, time in
}() }()
defer span.Finish() defer span.Finish()
err := s.SessionStore.UpdateExpiresAt(sessionID, time) err := s.SessionStore.UpdateExpiresAt(sessionID, timestamp)
if err != nil { if err != nil {
span.LogFields(spanlog.Error(err)) span.LogFields(spanlog.Error(err))
ext.Error.Set(span, true) ext.Error.Set(span, true)
@@ -7657,7 +7676,7 @@ func (s *OpenTracingLayerSessionStore) UpdateExpiresAt(sessionID string, time in
return err 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() origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "SessionStore.UpdateLastActivityAt") span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "SessionStore.UpdateLastActivityAt")
s.Root.Store.SetContext(newCtx) s.Root.Store.SetContext(newCtx)
@@ -7666,7 +7685,7 @@ func (s *OpenTracingLayerSessionStore) UpdateLastActivityAt(sessionID string, ti
}() }()
defer span.Finish() defer span.Finish()
err := s.SessionStore.UpdateLastActivityAt(sessionID, time) err := s.SessionStore.UpdateLastActivityAt(sessionID, timestamp)
if err != nil { if err != nil {
span.LogFields(spanlog.Error(err)) span.LogFields(spanlog.Error(err))
ext.Error.Set(span, true) ext.Error.Set(span, true)
@@ -10000,7 +10019,7 @@ func (s *OpenTracingLayerUploadSessionStore) Update(session *model.UploadSession
return err 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() origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "UserStore.AnalyticsActiveCount") span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "UserStore.AnalyticsActiveCount")
s.Root.Store.SetContext(newCtx) s.Root.Store.SetContext(newCtx)
@@ -10009,7 +10028,7 @@ func (s *OpenTracingLayerUserStore) AnalyticsActiveCount(time int64, options mod
}() }()
defer span.Finish() defer span.Finish()
result, err := s.UserStore.AnalyticsActiveCount(time, options) result, err := s.UserStore.AnalyticsActiveCount(timestamp, options)
if err != nil { if err != nil {
span.LogFields(spanlog.Error(err)) span.LogFields(spanlog.Error(err))
ext.Error.Set(span, true) 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() origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "WebhookStore.DeleteIncoming") span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "WebhookStore.DeleteIncoming")
s.Root.Store.SetContext(newCtx) s.Root.Store.SetContext(newCtx)
@@ -11607,7 +11626,7 @@ func (s *OpenTracingLayerWebhookStore) DeleteIncoming(webhookID string, time int
}() }()
defer span.Finish() defer span.Finish()
err := s.WebhookStore.DeleteIncoming(webhookID, time) err := s.WebhookStore.DeleteIncoming(webhookID, timestamp)
if err != nil { if err != nil {
span.LogFields(spanlog.Error(err)) span.LogFields(spanlog.Error(err))
ext.Error.Set(span, true) ext.Error.Set(span, true)
@@ -11616,7 +11635,7 @@ func (s *OpenTracingLayerWebhookStore) DeleteIncoming(webhookID string, time int
return err 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() origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "WebhookStore.DeleteOutgoing") span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "WebhookStore.DeleteOutgoing")
s.Root.Store.SetContext(newCtx) s.Root.Store.SetContext(newCtx)
@@ -11625,7 +11644,7 @@ func (s *OpenTracingLayerWebhookStore) DeleteOutgoing(webhookID string, time int
}() }()
defer span.Finish() defer span.Finish()
err := s.WebhookStore.DeleteOutgoing(webhookID, time) err := s.WebhookStore.DeleteOutgoing(webhookID, timestamp)
if err != nil { if err != nil {
span.LogFields(spanlog.Error(err)) span.LogFields(spanlog.Error(err))
ext.Error.Set(span, true) ext.Error.Set(span, true)

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

@@ -8,6 +8,7 @@ package retrylayer
import ( import (
"context" "context"
"time"
timepkg "time" timepkg "time"
"github.com/go-sql-driver/mysql" "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 tries := 0
for { for {
err := s.ChannelStore.Delete(channelID, time) err := s.ChannelStore.Delete(channelID, timestamp)
if err == nil { if err == nil {
return 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 { func (s *RetryLayerChannelStore) RemoveAllDeactivatedMembers(channelID string) error {
tries := 0 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 tries := 0
for { for {
err := s.ChannelStore.Restore(channelID, time) err := s.ChannelStore.Restore(channelID, timestamp)
if err == nil { if err == nil {
return 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 tries := 0
for { for {
err := s.CommandStore.Delete(commandID, time) err := s.CommandStore.Delete(commandID, timestamp)
if err == nil { if err == nil {
return 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 tries := 0
for { for {
err := s.EmojiStore.Delete(emoji, time) err := s.EmojiStore.Delete(emoji, timestamp)
if err == nil { if err == nil {
return 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 tries := 0
for { for {
err := s.PostStore.Delete(postID, time, deleteByID) err := s.PostStore.Delete(postID, timestamp, deleteByID)
if err == nil { if err == nil {
return 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 tries := 0
for { for {
result, err := s.PostStore.GetPostAfterTime(channelID, time, collapsedThreads) result, err := s.PostStore.GetPostAfterTime(channelID, timestamp, collapsedThreads)
if err == nil { if err == nil {
return result, 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 tries := 0
for { for {
result, err := s.PostStore.GetPostIdAfterTime(channelID, time, collapsedThreads) result, err := s.PostStore.GetPostIdAfterTime(channelID, timestamp, collapsedThreads)
if err == nil { if err == nil {
return result, 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 tries := 0
for { for {
result, err := s.PostStore.GetPostIdBeforeTime(channelID, time, collapsedThreads) result, err := s.PostStore.GetPostIdBeforeTime(channelID, timestamp, collapsedThreads)
if err == nil { if err == nil {
return result, 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 tries := 0
for { for {
result, err := s.PostStore.GetPostsCreatedAt(channelID, time) result, err := s.PostStore.GetPostsCreatedAt(channelID, timestamp)
if err == nil { if err == nil {
return result, 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 tries := 0
for { for {
err := s.SessionStore.UpdateExpiresAt(sessionID, time) err := s.SessionStore.UpdateExpiresAt(sessionID, timestamp)
if err == nil { if err == nil {
return 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 tries := 0
for { for {
err := s.SessionStore.UpdateLastActivityAt(sessionID, time) err := s.SessionStore.UpdateLastActivityAt(sessionID, timestamp)
if err == nil { if err == nil {
return 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 tries := 0
for { for {
result, err := s.UserStore.AnalyticsActiveCount(time, options) result, err := s.UserStore.AnalyticsActiveCount(timestamp, options)
if err == nil { if err == nil {
return result, 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 tries := 0
for { for {
err := s.WebhookStore.DeleteIncoming(webhookID, time) err := s.WebhookStore.DeleteIncoming(webhookID, timestamp)
if err == nil { if err == nil {
return 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 tries := 0
for { for {
err := s.WebhookStore.DeleteOutgoing(webhookID, time) err := s.WebhookStore.DeleteOutgoing(webhookID, timestamp)
if err == nil { if err == nil {
return nil return nil
} }

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

@@ -4297,3 +4297,53 @@ func (s SqlChannelStore) GetTopChannelsForUserSince(userID string, teamID string
return model.GetTopChannelListWithPagination(channels, limit), nil 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) GetMany(ids []string, allowFromCache bool) (model.ChannelList, error)
InvalidateChannel(id string) InvalidateChannel(id string)
InvalidateChannelByName(teamID, name string) InvalidateChannelByName(teamID, name string)
Delete(channelID string, time int64) error Delete(channelID string, timestamp int64) error
Restore(channelID string, time int64) error Restore(channelID string, timestamp int64) error
SetDeleteAt(channelID string, deleteAt int64, updateAt int64) error SetDeleteAt(channelID string, deleteAt int64, updateAt int64) error
PermanentDelete(channelID string) error PermanentDelete(channelID string) error
PermanentDeleteByTeam(teamID string) error PermanentDeleteByTeam(teamID string) error
@@ -293,6 +293,7 @@ type ChannelStore interface {
// Insights // Insights
GetTopChannelsForTeamSince(teamID string, userID string, since int64, offset int, limit int) (*model.TopChannelList, error) 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) 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 { type ChannelMemberHistoryStore interface {
@@ -338,7 +339,7 @@ type PostStore interface {
Update(newPost *model.Post, oldPost *model.Post) (*model.Post, error) 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) 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) 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 PermanentDeleteByUser(userID string) error
PermanentDeleteByChannel(channelID string) error PermanentDeleteByChannel(channelID string) error
GetPosts(options model.GetPostsOptions, allowFromCache bool, sanitizeOptions map[string]bool) (*model.PostList, 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) GetPostsBefore(options model.GetPostsOptions, sanitizeOptions map[string]bool) (*model.PostList, error)
GetPostsAfter(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) GetPostsSince(options model.GetPostsSinceOptions, allowFromCache bool, sanitizeOptions map[string]bool) (*model.PostList, error)
GetPostAfterTime(channelID string, time int64, collapsedThreads bool) (*model.Post, error) GetPostAfterTime(channelID string, timestamp int64, collapsedThreads bool) (*model.Post, error)
GetPostIdAfterTime(channelID string, time int64, collapsedThreads bool) (string, error) GetPostIdAfterTime(channelID string, timestamp int64, collapsedThreads bool) (string, error)
GetPostIdBeforeTime(channelID string, time int64, collapsedThreads bool) (string, error) GetPostIdBeforeTime(channelID string, timestamp int64, collapsedThreads bool) (string, error)
GetEtag(channelID string, allowFromCache bool, collapsedThreads bool) string GetEtag(channelID string, allowFromCache bool, collapsedThreads bool) string
Search(teamID string, userID string, params *model.SearchParams) (*model.PostList, error) Search(teamID string, userID string, params *model.SearchParams) (*model.PostList, error)
AnalyticsUserCountsWithPostsByDay(teamID string) (model.AnalyticsRows, error) AnalyticsUserCountsWithPostsByDay(teamID string) (model.AnalyticsRows, error)
@@ -360,7 +361,7 @@ type PostStore interface {
ClearCaches() ClearCaches()
InvalidateLastPostTimeCache(channelID string) InvalidateLastPostTimeCache(channelID string)
GetLastPostRowCreateAt() (int64, error) 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) Overwrite(post *model.Post) (*model.Post, error)
OverwriteMultiple(posts []*model.Post) ([]*model.Post, int, error) OverwriteMultiple(posts []*model.Post) ([]*model.Post, int, error)
GetPostsByIds(postIds []string) ([]*model.Post, error) GetPostsByIds(postIds []string) ([]*model.Post, error)
@@ -422,7 +423,7 @@ type UserStore interface {
UpdateFailedPasswordAttempts(userID string, attempts int) error UpdateFailedPasswordAttempts(userID string, attempts int) error
GetSystemAdminProfiles() (map[string]*model.User, error) GetSystemAdminProfiles() (map[string]*model.User, error)
PermanentDelete(userID string) 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) AnalyticsActiveCountForPeriod(startTime int64, endTime int64, options model.UserCountOptions) (int64, error)
GetUnreadCount(userID string) (int64, error) GetUnreadCount(userID string) (int64, error)
GetUnreadCountForChannel(userID string, channelID string) (int64, error) GetUnreadCountForChannel(userID string, channelID string) (int64, error)
@@ -478,8 +479,8 @@ type SessionStore interface {
RemoveAllSessions() error RemoveAllSessions() error
PermanentDeleteSessionsByUser(teamID string) error PermanentDeleteSessionsByUser(teamID string) error
GetLastSessionRowCreateAt() (int64, error) GetLastSessionRowCreateAt() (int64, error)
UpdateExpiresAt(sessionID string, time int64) error UpdateExpiresAt(sessionID string, timestamp int64) error
UpdateLastActivityAt(sessionID string, time int64) error UpdateLastActivityAt(sessionID string, timestamp int64) error
UpdateRoles(userID string, roles string) (string, error) UpdateRoles(userID string, roles string) (string, error)
UpdateDeviceId(id string, deviceID string, expiresAt int64) (string, error) UpdateDeviceId(id string, deviceID string, expiresAt int64) (string, error)
UpdateProps(session *model.Session) error UpdateProps(session *model.Session) error
@@ -563,7 +564,7 @@ type WebhookStore interface {
GetIncomingByTeamByUser(teamID string, userID string, offset, limit int) ([]*model.IncomingWebhook, error) GetIncomingByTeamByUser(teamID string, userID string, offset, limit int) ([]*model.IncomingWebhook, error)
UpdateIncoming(webhook *model.IncomingWebhook) (*model.IncomingWebhook, error) UpdateIncoming(webhook *model.IncomingWebhook) (*model.IncomingWebhook, error)
GetIncomingByChannel(channelID string) ([]*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 PermanentDeleteIncomingByChannel(channelID string) error
PermanentDeleteIncomingByUser(userID string) error PermanentDeleteIncomingByUser(userID string) error
@@ -575,7 +576,7 @@ type WebhookStore interface {
GetOutgoingListByUser(userID string, offset, limit int) ([]*model.OutgoingWebhook, error) GetOutgoingListByUser(userID string, offset, limit int) ([]*model.OutgoingWebhook, error)
GetOutgoingByTeam(teamID 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) 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 PermanentDeleteOutgoingByChannel(channelID string) error
PermanentDeleteOutgoingByUser(userID string) error PermanentDeleteOutgoingByUser(userID string) error
UpdateOutgoing(hook *model.OutgoingWebhook) (*model.OutgoingWebhook, error) UpdateOutgoing(hook *model.OutgoingWebhook) (*model.OutgoingWebhook, error)
@@ -591,7 +592,7 @@ type CommandStore interface {
GetByTrigger(teamID string, trigger string) (*model.Command, error) GetByTrigger(teamID string, trigger string) (*model.Command, error)
Get(id string) (*model.Command, error) Get(id string) (*model.Command, error)
GetByTeam(teamID 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 PermanentDeleteByTeam(teamID string) error
PermanentDeleteByUser(userID string) error PermanentDeleteByUser(userID string) error
Update(hook *model.Command) (*model.Command, 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) GetByName(ctx context.Context, name string, allowFromCache bool) (*model.Emoji, error)
GetMultipleByName(names []string) ([]*model.Emoji, error) GetMultipleByName(names []string) ([]*model.Emoji, error)
GetList(offset, limit int, sort 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) 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("UpdateSidebarChannelsByPreferences", func(t *testing.T) { testUpdateSidebarChannelsByPreferences(t, ss) })
t.Run("SetShared", func(t *testing.T) { testSetShared(t, ss) }) t.Run("SetShared", func(t *testing.T) { testSetShared(t, ss) })
t.Run("GetTeamForChannel", func(t *testing.T) { testGetTeamForChannel(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) { func testChannelStoreSave(t *testing.T, ss store.Store) {
@@ -7904,3 +7905,38 @@ func testGetTeamForChannel(t *testing.T, ss store.Store) {
var nfErr *store.ErrNotFound var nfErr *store.ErrNotFound
require.True(t, errors.As(err, &nfErr)) 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" mock "github.com/stretchr/testify/mock"
store "github.com/mattermost/mattermost-server/v6/store" store "github.com/mattermost/mattermost-server/v6/store"
time "time"
) )
// ChannelStore is an autogenerated mock type for the ChannelStore type // 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 return r0, r1
} }
// Delete provides a mock function with given fields: channelID, time // Delete provides a mock function with given fields: channelID, timestamp
func (_m *ChannelStore) Delete(channelID string, time int64) error { func (_m *ChannelStore) Delete(channelID string, timestamp int64) error {
ret := _m.Called(channelID, time) ret := _m.Called(channelID, timestamp)
var r0 error var r0 error
if rf, ok := ret.Get(0).(func(string, int64) error); ok { if rf, ok := ret.Get(0).(func(string, int64) error); ok {
r0 = rf(channelID, time) r0 = rf(channelID, timestamp)
} else { } else {
r0 = ret.Error(0) r0 = ret.Error(0)
} }
@@ -1717,6 +1719,29 @@ func (_m *ChannelStore) PermanentDeleteMembersByUser(userID string) error {
return r0 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 // RemoveAllDeactivatedMembers provides a mock function with given fields: channelID
func (_m *ChannelStore) RemoveAllDeactivatedMembers(channelID string) error { func (_m *ChannelStore) RemoveAllDeactivatedMembers(channelID string) error {
ret := _m.Called(channelID) ret := _m.Called(channelID)
@@ -1773,13 +1798,13 @@ func (_m *ChannelStore) ResetAllChannelSchemes() error {
return r0 return r0
} }
// Restore provides a mock function with given fields: channelID, time // Restore provides a mock function with given fields: channelID, timestamp
func (_m *ChannelStore) Restore(channelID string, time int64) error { func (_m *ChannelStore) Restore(channelID string, timestamp int64) error {
ret := _m.Called(channelID, time) ret := _m.Called(channelID, timestamp)
var r0 error var r0 error
if rf, ok := ret.Get(0).(func(string, int64) error); ok { if rf, ok := ret.Get(0).(func(string, int64) error); ok {
r0 = rf(channelID, time) r0 = rf(channelID, timestamp)
} else { } else {
r0 = ret.Error(0) r0 = ret.Error(0)
} }

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

@@ -35,13 +35,13 @@ func (_m *CommandStore) AnalyticsCommandCount(teamID string) (int64, error) {
return r0, r1 return r0, r1
} }
// Delete provides a mock function with given fields: commandID, time // Delete provides a mock function with given fields: commandID, timestamp
func (_m *CommandStore) Delete(commandID string, time int64) error { func (_m *CommandStore) Delete(commandID string, timestamp int64) error {
ret := _m.Called(commandID, time) ret := _m.Called(commandID, timestamp)
var r0 error var r0 error
if rf, ok := ret.Get(0).(func(string, int64) error); ok { if rf, ok := ret.Get(0).(func(string, int64) error); ok {
r0 = rf(commandID, time) r0 = rf(commandID, timestamp)
} else { } else {
r0 = ret.Error(0) r0 = ret.Error(0)
} }

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

@@ -16,13 +16,13 @@ type EmojiStore struct {
mock.Mock mock.Mock
} }
// Delete provides a mock function with given fields: emoji, time // Delete provides a mock function with given fields: emoji, timestamp
func (_m *EmojiStore) Delete(emoji *model.Emoji, time int64) error { func (_m *EmojiStore) Delete(emoji *model.Emoji, timestamp int64) error {
ret := _m.Called(emoji, time) ret := _m.Called(emoji, timestamp)
var r0 error var r0 error
if rf, ok := ret.Get(0).(func(*model.Emoji, int64) error); ok { if rf, ok := ret.Get(0).(func(*model.Emoji, int64) error); ok {
r0 = rf(emoji, time) r0 = rf(emoji, timestamp)
} else { } else {
r0 = ret.Error(0) r0 = ret.Error(0)
} }

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

@@ -88,13 +88,13 @@ func (_m *PostStore) ClearCaches() {
_m.Called() _m.Called()
} }
// Delete provides a mock function with given fields: postID, time, deleteByID // Delete provides a mock function with given fields: postID, timestamp, deleteByID
func (_m *PostStore) Delete(postID string, time int64, deleteByID string) error { func (_m *PostStore) Delete(postID string, timestamp int64, deleteByID string) error {
ret := _m.Called(postID, time, deleteByID) ret := _m.Called(postID, timestamp, deleteByID)
var r0 error var r0 error
if rf, ok := ret.Get(0).(func(string, int64, string) error); ok { if rf, ok := ret.Get(0).(func(string, int64, string) error); ok {
r0 = rf(postID, time, deleteByID) r0 = rf(postID, timestamp, deleteByID)
} else { } else {
r0 = ret.Error(0) r0 = ret.Error(0)
} }
@@ -354,13 +354,13 @@ func (_m *PostStore) GetParentsForExportAfter(limit int, afterID string) ([]*mod
return r0, r1 return r0, r1
} }
// GetPostAfterTime provides a mock function with given fields: channelID, time, collapsedThreads // GetPostAfterTime provides a mock function with given fields: channelID, timestamp, collapsedThreads
func (_m *PostStore) GetPostAfterTime(channelID string, time int64, collapsedThreads bool) (*model.Post, error) { func (_m *PostStore) GetPostAfterTime(channelID string, timestamp int64, collapsedThreads bool) (*model.Post, error) {
ret := _m.Called(channelID, time, collapsedThreads) ret := _m.Called(channelID, timestamp, collapsedThreads)
var r0 *model.Post var r0 *model.Post
if rf, ok := ret.Get(0).(func(string, int64, bool) *model.Post); ok { if rf, ok := ret.Get(0).(func(string, int64, bool) *model.Post); ok {
r0 = rf(channelID, time, collapsedThreads) r0 = rf(channelID, timestamp, collapsedThreads)
} else { } else {
if ret.Get(0) != nil { if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.Post) r0 = ret.Get(0).(*model.Post)
@@ -369,7 +369,7 @@ func (_m *PostStore) GetPostAfterTime(channelID string, time int64, collapsedThr
var r1 error var r1 error
if rf, ok := ret.Get(1).(func(string, int64, bool) error); ok { if rf, ok := ret.Get(1).(func(string, int64, bool) error); ok {
r1 = rf(channelID, time, collapsedThreads) r1 = rf(channelID, timestamp, collapsedThreads)
} else { } else {
r1 = ret.Error(1) r1 = ret.Error(1)
} }
@@ -377,20 +377,20 @@ func (_m *PostStore) GetPostAfterTime(channelID string, time int64, collapsedThr
return r0, r1 return r0, r1
} }
// GetPostIdAfterTime provides a mock function with given fields: channelID, time, collapsedThreads // GetPostIdAfterTime provides a mock function with given fields: channelID, timestamp, collapsedThreads
func (_m *PostStore) GetPostIdAfterTime(channelID string, time int64, collapsedThreads bool) (string, error) { func (_m *PostStore) GetPostIdAfterTime(channelID string, timestamp int64, collapsedThreads bool) (string, error) {
ret := _m.Called(channelID, time, collapsedThreads) ret := _m.Called(channelID, timestamp, collapsedThreads)
var r0 string var r0 string
if rf, ok := ret.Get(0).(func(string, int64, bool) string); ok { if rf, ok := ret.Get(0).(func(string, int64, bool) string); ok {
r0 = rf(channelID, time, collapsedThreads) r0 = rf(channelID, timestamp, collapsedThreads)
} else { } else {
r0 = ret.Get(0).(string) r0 = ret.Get(0).(string)
} }
var r1 error var r1 error
if rf, ok := ret.Get(1).(func(string, int64, bool) error); ok { if rf, ok := ret.Get(1).(func(string, int64, bool) error); ok {
r1 = rf(channelID, time, collapsedThreads) r1 = rf(channelID, timestamp, collapsedThreads)
} else { } else {
r1 = ret.Error(1) r1 = ret.Error(1)
} }
@@ -398,20 +398,20 @@ func (_m *PostStore) GetPostIdAfterTime(channelID string, time int64, collapsedT
return r0, r1 return r0, r1
} }
// GetPostIdBeforeTime provides a mock function with given fields: channelID, time, collapsedThreads // GetPostIdBeforeTime provides a mock function with given fields: channelID, timestamp, collapsedThreads
func (_m *PostStore) GetPostIdBeforeTime(channelID string, time int64, collapsedThreads bool) (string, error) { func (_m *PostStore) GetPostIdBeforeTime(channelID string, timestamp int64, collapsedThreads bool) (string, error) {
ret := _m.Called(channelID, time, collapsedThreads) ret := _m.Called(channelID, timestamp, collapsedThreads)
var r0 string var r0 string
if rf, ok := ret.Get(0).(func(string, int64, bool) string); ok { if rf, ok := ret.Get(0).(func(string, int64, bool) string); ok {
r0 = rf(channelID, time, collapsedThreads) r0 = rf(channelID, timestamp, collapsedThreads)
} else { } else {
r0 = ret.Get(0).(string) r0 = ret.Get(0).(string)
} }
var r1 error var r1 error
if rf, ok := ret.Get(1).(func(string, int64, bool) error); ok { if rf, ok := ret.Get(1).(func(string, int64, bool) error); ok {
r1 = rf(channelID, time, collapsedThreads) r1 = rf(channelID, timestamp, collapsedThreads)
} else { } else {
r1 = ret.Error(1) r1 = ret.Error(1)
} }
@@ -534,13 +534,13 @@ func (_m *PostStore) GetPostsByIds(postIds []string) ([]*model.Post, error) {
return r0, r1 return r0, r1
} }
// GetPostsCreatedAt provides a mock function with given fields: channelID, time // GetPostsCreatedAt provides a mock function with given fields: channelID, timestamp
func (_m *PostStore) GetPostsCreatedAt(channelID string, time int64) ([]*model.Post, error) { func (_m *PostStore) GetPostsCreatedAt(channelID string, timestamp int64) ([]*model.Post, error) {
ret := _m.Called(channelID, time) ret := _m.Called(channelID, timestamp)
var r0 []*model.Post var r0 []*model.Post
if rf, ok := ret.Get(0).(func(string, int64) []*model.Post); ok { if rf, ok := ret.Get(0).(func(string, int64) []*model.Post); ok {
r0 = rf(channelID, time) r0 = rf(channelID, timestamp)
} else { } else {
if ret.Get(0) != nil { if ret.Get(0) != nil {
r0 = ret.Get(0).([]*model.Post) r0 = ret.Get(0).([]*model.Post)
@@ -549,7 +549,7 @@ func (_m *PostStore) GetPostsCreatedAt(channelID string, time int64) ([]*model.P
var r1 error var r1 error
if rf, ok := ret.Get(1).(func(string, int64) error); ok { if rf, ok := ret.Get(1).(func(string, int64) error); ok {
r1 = rf(channelID, time) r1 = rf(channelID, timestamp)
} else { } else {
r1 = ret.Error(1) r1 = ret.Error(1)
} }

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

@@ -264,13 +264,13 @@ func (_m *SessionStore) UpdateExpiredNotify(sessionid string, notified bool) err
return r0 return r0
} }
// UpdateExpiresAt provides a mock function with given fields: sessionID, time // UpdateExpiresAt provides a mock function with given fields: sessionID, timestamp
func (_m *SessionStore) UpdateExpiresAt(sessionID string, time int64) error { func (_m *SessionStore) UpdateExpiresAt(sessionID string, timestamp int64) error {
ret := _m.Called(sessionID, time) ret := _m.Called(sessionID, timestamp)
var r0 error var r0 error
if rf, ok := ret.Get(0).(func(string, int64) error); ok { if rf, ok := ret.Get(0).(func(string, int64) error); ok {
r0 = rf(sessionID, time) r0 = rf(sessionID, timestamp)
} else { } else {
r0 = ret.Error(0) r0 = ret.Error(0)
} }
@@ -278,13 +278,13 @@ func (_m *SessionStore) UpdateExpiresAt(sessionID string, time int64) error {
return r0 return r0
} }
// UpdateLastActivityAt provides a mock function with given fields: sessionID, time // UpdateLastActivityAt provides a mock function with given fields: sessionID, timestamp
func (_m *SessionStore) UpdateLastActivityAt(sessionID string, time int64) error { func (_m *SessionStore) UpdateLastActivityAt(sessionID string, timestamp int64) error {
ret := _m.Called(sessionID, time) ret := _m.Called(sessionID, timestamp)
var r0 error var r0 error
if rf, ok := ret.Get(0).(func(string, int64) error); ok { if rf, ok := ret.Get(0).(func(string, int64) error); ok {
r0 = rf(sessionID, time) r0 = rf(sessionID, timestamp)
} else { } else {
r0 = ret.Error(0) r0 = ret.Error(0)
} }

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

@@ -18,20 +18,20 @@ type UserStore struct {
mock.Mock mock.Mock
} }
// AnalyticsActiveCount provides a mock function with given fields: time, options // AnalyticsActiveCount provides a mock function with given fields: timestamp, options
func (_m *UserStore) AnalyticsActiveCount(time int64, options model.UserCountOptions) (int64, error) { func (_m *UserStore) AnalyticsActiveCount(timestamp int64, options model.UserCountOptions) (int64, error) {
ret := _m.Called(time, options) ret := _m.Called(timestamp, options)
var r0 int64 var r0 int64
if rf, ok := ret.Get(0).(func(int64, model.UserCountOptions) int64); ok { if rf, ok := ret.Get(0).(func(int64, model.UserCountOptions) int64); ok {
r0 = rf(time, options) r0 = rf(timestamp, options)
} else { } else {
r0 = ret.Get(0).(int64) r0 = ret.Get(0).(int64)
} }
var r1 error var r1 error
if rf, ok := ret.Get(1).(func(int64, model.UserCountOptions) error); ok { if rf, ok := ret.Get(1).(func(int64, model.UserCountOptions) error); ok {
r1 = rf(time, options) r1 = rf(timestamp, options)
} else { } else {
r1 = ret.Error(1) r1 = ret.Error(1)
} }

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

@@ -61,13 +61,13 @@ func (_m *WebhookStore) ClearCaches() {
_m.Called() _m.Called()
} }
// DeleteIncoming provides a mock function with given fields: webhookID, time // DeleteIncoming provides a mock function with given fields: webhookID, timestamp
func (_m *WebhookStore) DeleteIncoming(webhookID string, time int64) error { func (_m *WebhookStore) DeleteIncoming(webhookID string, timestamp int64) error {
ret := _m.Called(webhookID, time) ret := _m.Called(webhookID, timestamp)
var r0 error var r0 error
if rf, ok := ret.Get(0).(func(string, int64) error); ok { if rf, ok := ret.Get(0).(func(string, int64) error); ok {
r0 = rf(webhookID, time) r0 = rf(webhookID, timestamp)
} else { } else {
r0 = ret.Error(0) r0 = ret.Error(0)
} }
@@ -75,13 +75,13 @@ func (_m *WebhookStore) DeleteIncoming(webhookID string, time int64) error {
return r0 return r0
} }
// DeleteOutgoing provides a mock function with given fields: webhookID, time // DeleteOutgoing provides a mock function with given fields: webhookID, timestamp
func (_m *WebhookStore) DeleteOutgoing(webhookID string, time int64) error { func (_m *WebhookStore) DeleteOutgoing(webhookID string, timestamp int64) error {
ret := _m.Called(webhookID, time) ret := _m.Called(webhookID, timestamp)
var r0 error var r0 error
if rf, ok := ret.Get(0).(func(string, int64) error); ok { if rf, ok := ret.Get(0).(func(string, int64) error); ok {
r0 = rf(webhookID, time) r0 = rf(webhookID, timestamp)
} else { } else {
r0 = ret.Error(0) 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("GetPosts", func(t *testing.T) { testPostStoreGetPosts(t, ss) })
t.Run("GetPostBeforeAfter", func(t *testing.T) { testPostStoreGetPostBeforeAfter(t, ss) }) t.Run("GetPostBeforeAfter", func(t *testing.T) { testPostStoreGetPostBeforeAfter(t, ss) })
t.Run("UserCountsWithPostsByDay", func(t *testing.T) { testUserCountsWithPostsByDay(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("GetFlaggedPostsForTeam", func(t *testing.T) { testPostStoreGetFlaggedPostsForTeam(t, ss, s) })
t.Run("GetFlaggedPosts", func(t *testing.T) { testPostStoreGetFlaggedPosts(t, ss) }) t.Run("GetFlaggedPosts", func(t *testing.T) { testPostStoreGetFlaggedPosts(t, ss) })
t.Run("GetFlaggedPostsForChannel", func(t *testing.T) { testPostStoreGetFlaggedPostsForChannel(t, ss) }) t.Run("GetFlaggedPostsForChannel", func(t *testing.T) { testPostStoreGetFlaggedPostsForChannel(t, ss) })

Разница между файлами не показана из-за своего большого размера Загрузить разницу