MM-43956: Adds post counts by duration. (#20131)
* MM-43956: Adds post counts by day. * MM-43956: Test data cleanup. Switch from Unix to UnixMilli. * MM-43956: Changes from selecting date data types to strings in SQL. * MM-43956: Fixes date format key. * MM-43956: Adds missing user id scope for 'my' top channels graph. * MM-43956: Adds the ability to group post counts by hour. * MM-43956: Require enterprise or professional license. Reject guests. * MM-43956: Adds license for tests. * MM-43956: Renames function. * MM-43956: Omits future hours from post counts by hour. * MM-43956: Adjust API response grouping to users timezone. * MM-43956: Adds translation. * MM-43956: Adds user's timezone to the data tier for the grouping by day and hour. * MM-43956: Fixes layers. * MM-43956: Lint fix. * MM-43956: Fix store layers. * MM-43956: Switches to default name for time package; changes parameter names to avoid naming conflict. * MM-43956: Updates mocks. Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
c03eb778c8
Коммит
182ae1234a
@@ -148,6 +148,7 @@ func TestChannelStore(t *testing.T, ss store.Store, s SqlStore) {
|
||||
t.Run("UpdateSidebarChannelsByPreferences", func(t *testing.T) { testUpdateSidebarChannelsByPreferences(t, ss) })
|
||||
t.Run("SetShared", func(t *testing.T) { testSetShared(t, ss) })
|
||||
t.Run("GetTeamForChannel", func(t *testing.T) { testGetTeamForChannel(t, ss) })
|
||||
t.Run("PostCountsByDuration", func(t *testing.T) { testChannelPostCountsByDuration(t, ss) })
|
||||
}
|
||||
|
||||
func testChannelStoreSave(t *testing.T, ss store.Store) {
|
||||
@@ -7904,3 +7905,38 @@ func testGetTeamForChannel(t *testing.T, ss store.Store) {
|
||||
var nfErr *store.ErrNotFound
|
||||
require.True(t, errors.As(err, &nfErr))
|
||||
}
|
||||
|
||||
func testChannelPostCountsByDuration(t *testing.T, ss store.Store) {
|
||||
team, err := ss.Team().Save(&model.Team{
|
||||
Name: model.NewId(),
|
||||
DisplayName: "DisplayName",
|
||||
Email: MakeEmail(),
|
||||
Type: model.TeamOpen,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
defer func() { ss.Team().PermanentDelete(team.Id) }()
|
||||
|
||||
channel := &model.Channel{
|
||||
TeamId: team.Id,
|
||||
DisplayName: "test_share_flag",
|
||||
Name: "test_share_flag",
|
||||
Type: model.ChannelTypeOpen,
|
||||
}
|
||||
channelSaved, err := ss.Channel().Save(channel, 999)
|
||||
require.NoError(t, err)
|
||||
defer func() { ss.Channel().PermanentDelete(channelSaved.Id) }()
|
||||
|
||||
userID := model.NewId()
|
||||
_, err = ss.Post().Save(&model.Post{
|
||||
UserId: userID,
|
||||
ChannelId: channel.Id,
|
||||
Message: "test",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
dpc, err := ss.Channel().PostCountsByDuration([]string{channelSaved.Id}, 0, &userID, model.PostsByDay, time.Now().Location())
|
||||
require.NoError(t, err)
|
||||
require.Len(t, dpc, 1)
|
||||
require.Equal(t, channel.Id, dpc[0].ChannelID)
|
||||
require.Equal(t, 1, dpc[0].PostCount)
|
||||
}
|
||||
|
||||
@@ -11,6 +11,8 @@ import (
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
|
||||
store "github.com/mattermost/mattermost-server/v6/store"
|
||||
|
||||
time "time"
|
||||
)
|
||||
|
||||
// ChannelStore is an autogenerated mock type for the ChannelStore type
|
||||
@@ -266,13 +268,13 @@ func (_m *ChannelStore) CreateSidebarCategory(userID string, teamID string, newC
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Delete provides a mock function with given fields: channelID, time
|
||||
func (_m *ChannelStore) Delete(channelID string, time int64) error {
|
||||
ret := _m.Called(channelID, time)
|
||||
// Delete provides a mock function with given fields: channelID, timestamp
|
||||
func (_m *ChannelStore) Delete(channelID string, timestamp int64) error {
|
||||
ret := _m.Called(channelID, timestamp)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(string, int64) error); ok {
|
||||
r0 = rf(channelID, time)
|
||||
r0 = rf(channelID, timestamp)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
@@ -1717,6 +1719,29 @@ func (_m *ChannelStore) PermanentDeleteMembersByUser(userID string) error {
|
||||
return r0
|
||||
}
|
||||
|
||||
// PostCountsByDuration provides a mock function with given fields: channelIDs, sinceUnixMillis, userID, duration, groupingLocation
|
||||
func (_m *ChannelStore) PostCountsByDuration(channelIDs []string, sinceUnixMillis int64, userID *string, duration model.PostCountGrouping, groupingLocation *time.Location) ([]*model.DurationPostCount, error) {
|
||||
ret := _m.Called(channelIDs, sinceUnixMillis, userID, duration, groupingLocation)
|
||||
|
||||
var r0 []*model.DurationPostCount
|
||||
if rf, ok := ret.Get(0).(func([]string, int64, *string, model.PostCountGrouping, *time.Location) []*model.DurationPostCount); ok {
|
||||
r0 = rf(channelIDs, sinceUnixMillis, userID, duration, groupingLocation)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]*model.DurationPostCount)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func([]string, int64, *string, model.PostCountGrouping, *time.Location) error); ok {
|
||||
r1 = rf(channelIDs, sinceUnixMillis, userID, duration, groupingLocation)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// RemoveAllDeactivatedMembers provides a mock function with given fields: channelID
|
||||
func (_m *ChannelStore) RemoveAllDeactivatedMembers(channelID string) error {
|
||||
ret := _m.Called(channelID)
|
||||
@@ -1773,13 +1798,13 @@ func (_m *ChannelStore) ResetAllChannelSchemes() error {
|
||||
return r0
|
||||
}
|
||||
|
||||
// Restore provides a mock function with given fields: channelID, time
|
||||
func (_m *ChannelStore) Restore(channelID string, time int64) error {
|
||||
ret := _m.Called(channelID, time)
|
||||
// Restore provides a mock function with given fields: channelID, timestamp
|
||||
func (_m *ChannelStore) Restore(channelID string, timestamp int64) error {
|
||||
ret := _m.Called(channelID, timestamp)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(string, int64) error); ok {
|
||||
r0 = rf(channelID, time)
|
||||
r0 = rf(channelID, timestamp)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
@@ -35,13 +35,13 @@ func (_m *CommandStore) AnalyticsCommandCount(teamID string) (int64, error) {
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Delete provides a mock function with given fields: commandID, time
|
||||
func (_m *CommandStore) Delete(commandID string, time int64) error {
|
||||
ret := _m.Called(commandID, time)
|
||||
// Delete provides a mock function with given fields: commandID, timestamp
|
||||
func (_m *CommandStore) Delete(commandID string, timestamp int64) error {
|
||||
ret := _m.Called(commandID, timestamp)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(string, int64) error); ok {
|
||||
r0 = rf(commandID, time)
|
||||
r0 = rf(commandID, timestamp)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
@@ -16,13 +16,13 @@ type EmojiStore struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// Delete provides a mock function with given fields: emoji, time
|
||||
func (_m *EmojiStore) Delete(emoji *model.Emoji, time int64) error {
|
||||
ret := _m.Called(emoji, time)
|
||||
// Delete provides a mock function with given fields: emoji, timestamp
|
||||
func (_m *EmojiStore) Delete(emoji *model.Emoji, timestamp int64) error {
|
||||
ret := _m.Called(emoji, timestamp)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(*model.Emoji, int64) error); ok {
|
||||
r0 = rf(emoji, time)
|
||||
r0 = rf(emoji, timestamp)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
@@ -88,13 +88,13 @@ func (_m *PostStore) ClearCaches() {
|
||||
_m.Called()
|
||||
}
|
||||
|
||||
// Delete provides a mock function with given fields: postID, time, deleteByID
|
||||
func (_m *PostStore) Delete(postID string, time int64, deleteByID string) error {
|
||||
ret := _m.Called(postID, time, deleteByID)
|
||||
// Delete provides a mock function with given fields: postID, timestamp, deleteByID
|
||||
func (_m *PostStore) Delete(postID string, timestamp int64, deleteByID string) error {
|
||||
ret := _m.Called(postID, timestamp, deleteByID)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(string, int64, string) error); ok {
|
||||
r0 = rf(postID, time, deleteByID)
|
||||
r0 = rf(postID, timestamp, deleteByID)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
@@ -354,13 +354,13 @@ func (_m *PostStore) GetParentsForExportAfter(limit int, afterID string) ([]*mod
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetPostAfterTime provides a mock function with given fields: channelID, time, collapsedThreads
|
||||
func (_m *PostStore) GetPostAfterTime(channelID string, time int64, collapsedThreads bool) (*model.Post, error) {
|
||||
ret := _m.Called(channelID, time, collapsedThreads)
|
||||
// GetPostAfterTime provides a mock function with given fields: channelID, timestamp, collapsedThreads
|
||||
func (_m *PostStore) GetPostAfterTime(channelID string, timestamp int64, collapsedThreads bool) (*model.Post, error) {
|
||||
ret := _m.Called(channelID, timestamp, collapsedThreads)
|
||||
|
||||
var r0 *model.Post
|
||||
if rf, ok := ret.Get(0).(func(string, int64, bool) *model.Post); ok {
|
||||
r0 = rf(channelID, time, collapsedThreads)
|
||||
r0 = rf(channelID, timestamp, collapsedThreads)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*model.Post)
|
||||
@@ -369,7 +369,7 @@ func (_m *PostStore) GetPostAfterTime(channelID string, time int64, collapsedThr
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(string, int64, bool) error); ok {
|
||||
r1 = rf(channelID, time, collapsedThreads)
|
||||
r1 = rf(channelID, timestamp, collapsedThreads)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
@@ -377,20 +377,20 @@ func (_m *PostStore) GetPostAfterTime(channelID string, time int64, collapsedThr
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetPostIdAfterTime provides a mock function with given fields: channelID, time, collapsedThreads
|
||||
func (_m *PostStore) GetPostIdAfterTime(channelID string, time int64, collapsedThreads bool) (string, error) {
|
||||
ret := _m.Called(channelID, time, collapsedThreads)
|
||||
// GetPostIdAfterTime provides a mock function with given fields: channelID, timestamp, collapsedThreads
|
||||
func (_m *PostStore) GetPostIdAfterTime(channelID string, timestamp int64, collapsedThreads bool) (string, error) {
|
||||
ret := _m.Called(channelID, timestamp, collapsedThreads)
|
||||
|
||||
var r0 string
|
||||
if rf, ok := ret.Get(0).(func(string, int64, bool) string); ok {
|
||||
r0 = rf(channelID, time, collapsedThreads)
|
||||
r0 = rf(channelID, timestamp, collapsedThreads)
|
||||
} else {
|
||||
r0 = ret.Get(0).(string)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(string, int64, bool) error); ok {
|
||||
r1 = rf(channelID, time, collapsedThreads)
|
||||
r1 = rf(channelID, timestamp, collapsedThreads)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
@@ -398,20 +398,20 @@ func (_m *PostStore) GetPostIdAfterTime(channelID string, time int64, collapsedT
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetPostIdBeforeTime provides a mock function with given fields: channelID, time, collapsedThreads
|
||||
func (_m *PostStore) GetPostIdBeforeTime(channelID string, time int64, collapsedThreads bool) (string, error) {
|
||||
ret := _m.Called(channelID, time, collapsedThreads)
|
||||
// GetPostIdBeforeTime provides a mock function with given fields: channelID, timestamp, collapsedThreads
|
||||
func (_m *PostStore) GetPostIdBeforeTime(channelID string, timestamp int64, collapsedThreads bool) (string, error) {
|
||||
ret := _m.Called(channelID, timestamp, collapsedThreads)
|
||||
|
||||
var r0 string
|
||||
if rf, ok := ret.Get(0).(func(string, int64, bool) string); ok {
|
||||
r0 = rf(channelID, time, collapsedThreads)
|
||||
r0 = rf(channelID, timestamp, collapsedThreads)
|
||||
} else {
|
||||
r0 = ret.Get(0).(string)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(string, int64, bool) error); ok {
|
||||
r1 = rf(channelID, time, collapsedThreads)
|
||||
r1 = rf(channelID, timestamp, collapsedThreads)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
@@ -534,13 +534,13 @@ func (_m *PostStore) GetPostsByIds(postIds []string) ([]*model.Post, error) {
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetPostsCreatedAt provides a mock function with given fields: channelID, time
|
||||
func (_m *PostStore) GetPostsCreatedAt(channelID string, time int64) ([]*model.Post, error) {
|
||||
ret := _m.Called(channelID, time)
|
||||
// GetPostsCreatedAt provides a mock function with given fields: channelID, timestamp
|
||||
func (_m *PostStore) GetPostsCreatedAt(channelID string, timestamp int64) ([]*model.Post, error) {
|
||||
ret := _m.Called(channelID, timestamp)
|
||||
|
||||
var r0 []*model.Post
|
||||
if rf, ok := ret.Get(0).(func(string, int64) []*model.Post); ok {
|
||||
r0 = rf(channelID, time)
|
||||
r0 = rf(channelID, timestamp)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]*model.Post)
|
||||
@@ -549,7 +549,7 @@ func (_m *PostStore) GetPostsCreatedAt(channelID string, time int64) ([]*model.P
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(string, int64) error); ok {
|
||||
r1 = rf(channelID, time)
|
||||
r1 = rf(channelID, timestamp)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
@@ -264,13 +264,13 @@ func (_m *SessionStore) UpdateExpiredNotify(sessionid string, notified bool) err
|
||||
return r0
|
||||
}
|
||||
|
||||
// UpdateExpiresAt provides a mock function with given fields: sessionID, time
|
||||
func (_m *SessionStore) UpdateExpiresAt(sessionID string, time int64) error {
|
||||
ret := _m.Called(sessionID, time)
|
||||
// UpdateExpiresAt provides a mock function with given fields: sessionID, timestamp
|
||||
func (_m *SessionStore) UpdateExpiresAt(sessionID string, timestamp int64) error {
|
||||
ret := _m.Called(sessionID, timestamp)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(string, int64) error); ok {
|
||||
r0 = rf(sessionID, time)
|
||||
r0 = rf(sessionID, timestamp)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
@@ -278,13 +278,13 @@ func (_m *SessionStore) UpdateExpiresAt(sessionID string, time int64) error {
|
||||
return r0
|
||||
}
|
||||
|
||||
// UpdateLastActivityAt provides a mock function with given fields: sessionID, time
|
||||
func (_m *SessionStore) UpdateLastActivityAt(sessionID string, time int64) error {
|
||||
ret := _m.Called(sessionID, time)
|
||||
// UpdateLastActivityAt provides a mock function with given fields: sessionID, timestamp
|
||||
func (_m *SessionStore) UpdateLastActivityAt(sessionID string, timestamp int64) error {
|
||||
ret := _m.Called(sessionID, timestamp)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(string, int64) error); ok {
|
||||
r0 = rf(sessionID, time)
|
||||
r0 = rf(sessionID, timestamp)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
@@ -18,20 +18,20 @@ type UserStore struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// AnalyticsActiveCount provides a mock function with given fields: time, options
|
||||
func (_m *UserStore) AnalyticsActiveCount(time int64, options model.UserCountOptions) (int64, error) {
|
||||
ret := _m.Called(time, options)
|
||||
// AnalyticsActiveCount provides a mock function with given fields: timestamp, options
|
||||
func (_m *UserStore) AnalyticsActiveCount(timestamp int64, options model.UserCountOptions) (int64, error) {
|
||||
ret := _m.Called(timestamp, options)
|
||||
|
||||
var r0 int64
|
||||
if rf, ok := ret.Get(0).(func(int64, model.UserCountOptions) int64); ok {
|
||||
r0 = rf(time, options)
|
||||
r0 = rf(timestamp, options)
|
||||
} else {
|
||||
r0 = ret.Get(0).(int64)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(int64, model.UserCountOptions) error); ok {
|
||||
r1 = rf(time, options)
|
||||
r1 = rf(timestamp, options)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
@@ -61,13 +61,13 @@ func (_m *WebhookStore) ClearCaches() {
|
||||
_m.Called()
|
||||
}
|
||||
|
||||
// DeleteIncoming provides a mock function with given fields: webhookID, time
|
||||
func (_m *WebhookStore) DeleteIncoming(webhookID string, time int64) error {
|
||||
ret := _m.Called(webhookID, time)
|
||||
// DeleteIncoming provides a mock function with given fields: webhookID, timestamp
|
||||
func (_m *WebhookStore) DeleteIncoming(webhookID string, timestamp int64) error {
|
||||
ret := _m.Called(webhookID, timestamp)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(string, int64) error); ok {
|
||||
r0 = rf(webhookID, time)
|
||||
r0 = rf(webhookID, timestamp)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
@@ -75,13 +75,13 @@ func (_m *WebhookStore) DeleteIncoming(webhookID string, time int64) error {
|
||||
return r0
|
||||
}
|
||||
|
||||
// DeleteOutgoing provides a mock function with given fields: webhookID, time
|
||||
func (_m *WebhookStore) DeleteOutgoing(webhookID string, time int64) error {
|
||||
ret := _m.Called(webhookID, time)
|
||||
// DeleteOutgoing provides a mock function with given fields: webhookID, timestamp
|
||||
func (_m *WebhookStore) DeleteOutgoing(webhookID string, timestamp int64) error {
|
||||
ret := _m.Called(webhookID, timestamp)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(string, int64) error); ok {
|
||||
r0 = rf(webhookID, time)
|
||||
r0 = rf(webhookID, timestamp)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ func TestPostStore(t *testing.T, ss store.Store, s SqlStore) {
|
||||
t.Run("GetPosts", func(t *testing.T) { testPostStoreGetPosts(t, ss) })
|
||||
t.Run("GetPostBeforeAfter", func(t *testing.T) { testPostStoreGetPostBeforeAfter(t, ss) })
|
||||
t.Run("UserCountsWithPostsByDay", func(t *testing.T) { testUserCountsWithPostsByDay(t, ss) })
|
||||
t.Run("PostCountsByDay", func(t *testing.T) { testPostCountsByDay(t, ss) })
|
||||
t.Run("PostCountsByDuration", func(t *testing.T) { testPostCountsByDay(t, ss) })
|
||||
t.Run("GetFlaggedPostsForTeam", func(t *testing.T) { testPostStoreGetFlaggedPostsForTeam(t, ss, s) })
|
||||
t.Run("GetFlaggedPosts", func(t *testing.T) { testPostStoreGetFlaggedPosts(t, ss) })
|
||||
t.Run("GetFlaggedPostsForChannel", func(t *testing.T) { testPostStoreGetFlaggedPostsForChannel(t, ss) })
|
||||
|
||||
Ссылка в новой задаче
Block a user