[MM-14720] Add Posts Per Day Analytics and Number Posts Previous Day Functionality (#11402)

* Add ability to get bot counts per day

Modify tests using AnalyticsPostCountsByDay to include extra input
(botsOnly)

Correctly generate the mock file with 'make store-mocks' target.  Didn't
see these comments earlier

* Initial commit for calculating total posts previous day and total posts
from bots previous day

* - Refactor to use asserts instead of if statements in tests
- Capture inputs to AnalyticsPostCountsByDay() function into an
  options struct
- Remove bot creation from diagnostics_test.go.

* Remove utils library

* create AnalyticsPostCountsOptions struct which is accepted as an input
to AnalyticsPostCountsByDay method

* Go vet fixes
Этот коммит содержится в:
jfrerich
2019-07-02 16:10:22 -05:00
коммит произвёл Christopher Speller
родитель c8fb1b6265
Коммит 95652da0b8
7 изменённых файлов: 123 добавлений и 27 удалений

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

@@ -181,13 +181,26 @@ func (a *App) GetAnalytics(name string, teamId string) (model.AnalyticsRows, *mo
rows[9].Value = float64(r.Data.(int64)) rows[9].Value = float64(r.Data.(int64))
return rows, nil return rows, nil
} else if name == "bot_post_counts_day" {
if skipIntensiveQueries {
rows := model.AnalyticsRows{&model.AnalyticsRow{Name: "", Value: -1}}
return rows, nil
}
return a.Srv.Store.Post().AnalyticsPostCountsByDay(&model.AnalyticsPostCountsOptions{
TeamId: teamId,
BotsOnly: true,
YesterdayOnly: false,
})
} else if name == "post_counts_day" { } else if name == "post_counts_day" {
if skipIntensiveQueries { if skipIntensiveQueries {
rows := model.AnalyticsRows{&model.AnalyticsRow{Name: "", Value: -1}} rows := model.AnalyticsRows{&model.AnalyticsRow{Name: "", Value: -1}}
return rows, nil return rows, nil
} }
return a.Srv.Store.Post().AnalyticsPostCountsByDay(&model.AnalyticsPostCountsOptions{
return a.Srv.Store.Post().AnalyticsPostCountsByDay(teamId) TeamId: teamId,
BotsOnly: false,
YesterdayOnly: false,
})
} else if name == "user_counts_with_posts_day" { } else if name == "user_counts_with_posts_day" {
if skipIntensiveQueries { if skipIntensiveQueries {
rows := model.AnalyticsRows{&model.AnalyticsRow{Name: "", Value: -1}} rows := model.AnalyticsRows{&model.AnalyticsRow{Name: "", Value: -1}}

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

@@ -134,6 +134,8 @@ func (a *App) trackActivity() {
var deletedPublicChannelCount int64 var deletedPublicChannelCount int64
var deletedPrivateChannelCount int64 var deletedPrivateChannelCount int64
var postsCount int64 var postsCount int64
var postsCountPreviousDay int64
var botPostsCountPreviousDay int64
var slashCommandsCount int64 var slashCommandsCount int64
var incomingWebhooksCount int64 var incomingWebhooksCount int64
var outgoingWebhooksCount int64 var outgoingWebhooksCount int64
@@ -188,6 +190,20 @@ func (a *App) trackActivity() {
postsCount, _ = a.Srv.Store.Post().AnalyticsPostCount("", false, false) postsCount, _ = a.Srv.Store.Post().AnalyticsPostCount("", false, false)
postCountsOptions := &model.AnalyticsPostCountsOptions{TeamId: "", BotsOnly: false, YesterdayOnly: true}
postCountsYesterday, _ := a.Srv.Store.Post().AnalyticsPostCountsByDay(postCountsOptions)
postsCountPreviousDay = 0
if len(postCountsYesterday) > 0 {
postsCountPreviousDay = int64(postCountsYesterday[0].Value)
}
postCountsOptions = &model.AnalyticsPostCountsOptions{TeamId: "", BotsOnly: true, YesterdayOnly: true}
botPostCountsYesterday, _ := a.Srv.Store.Post().AnalyticsPostCountsByDay(postCountsOptions)
botPostsCountPreviousDay = 0
if len(botPostCountsYesterday) > 0 {
botPostsCountPreviousDay = int64(botPostCountsYesterday[0].Value)
}
slashCommandsCount, _ = a.Srv.Store.Command().AnalyticsCommandCount("") slashCommandsCount, _ = a.Srv.Store.Command().AnalyticsCommandCount("")
if c, err := a.Srv.Store.Webhook().AnalyticsIncomingCount(""); err == nil { if c, err := a.Srv.Store.Webhook().AnalyticsIncomingCount(""); err == nil {
@@ -208,6 +224,8 @@ func (a *App) trackActivity() {
"direct_message_channels": directChannelCount, "direct_message_channels": directChannelCount,
"public_channels_deleted": deletedPublicChannelCount, "public_channels_deleted": deletedPublicChannelCount,
"private_channels_deleted": deletedPrivateChannelCount, "private_channels_deleted": deletedPrivateChannelCount,
"posts_previous_day": postsCountPreviousDay,
"bot_posts_previous_day": botPostsCountPreviousDay,
"posts": postsCount, "posts": postsCount,
"slash_commands": slashCommandsCount, "slash_commands": slashCommandsCount,
"incoming_webhooks": incomingWebhooksCount, "incoming_webhooks": incomingWebhooksCount,

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

@@ -108,6 +108,12 @@ type SearchParameter struct {
IncludeDeletedChannels *bool `json:"include_deleted_channels"` IncludeDeletedChannels *bool `json:"include_deleted_channels"`
} }
type AnalyticsPostCountsOptions struct {
TeamId string
BotsOnly bool
YesterdayOnly bool
}
func (o *PostPatch) WithRewrittenImageURLs(f func(string) string) *PostPatch { func (o *PostPatch) WithRewrittenImageURLs(f func(string) string) *PostPatch {
copy := *o copy := *o
if copy.Message != nil { if copy.Message != nil {

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

@@ -991,14 +991,19 @@ func (s *SqlPostStore) AnalyticsUserCountsWithPostsByDay(teamId string) (model.A
return rows, nil return rows, nil
} }
func (s *SqlPostStore) AnalyticsPostCountsByDay(teamId string) (model.AnalyticsRows, *model.AppError) { func (s *SqlPostStore) AnalyticsPostCountsByDay(options *model.AnalyticsPostCountsOptions) (model.AnalyticsRows, *model.AppError) {
query := query :=
`SELECT `SELECT
DATE(FROM_UNIXTIME(Posts.CreateAt / 1000)) AS Name, DATE(FROM_UNIXTIME(Posts.CreateAt / 1000)) AS Name,
COUNT(Posts.Id) AS Value COUNT(Posts.Id) AS Value
FROM Posts` FROM Posts`
if len(teamId) > 0 { if options.BotsOnly {
query += " INNER JOIN Bots ON Posts.UserId = Bots.Userid"
}
if len(options.TeamId) > 0 {
query += " INNER JOIN Channels ON Posts.ChannelId = Channels.Id AND Channels.TeamId = :TeamId AND" query += " INNER JOIN Channels ON Posts.ChannelId = Channels.Id AND Channels.TeamId = :TeamId AND"
} else { } else {
query += " WHERE" query += " WHERE"
@@ -1016,7 +1021,11 @@ func (s *SqlPostStore) AnalyticsPostCountsByDay(teamId string) (model.AnalyticsR
TO_CHAR(DATE(TO_TIMESTAMP(Posts.CreateAt / 1000)), 'YYYY-MM-DD') AS Name, Count(Posts.Id) AS Value TO_CHAR(DATE(TO_TIMESTAMP(Posts.CreateAt / 1000)), 'YYYY-MM-DD') AS Name, Count(Posts.Id) AS Value
FROM Posts` FROM Posts`
if len(teamId) > 0 { if options.BotsOnly {
query += " INNER JOIN Bots ON Posts.UserId = Bots.Userid"
}
if len(options.TeamId) > 0 {
query += " INNER JOIN Channels ON Posts.ChannelId = Channels.Id AND Channels.TeamId = :TeamId AND" query += " INNER JOIN Channels ON Posts.ChannelId = Channels.Id AND Channels.TeamId = :TeamId AND"
} else { } else {
query += " WHERE" query += " WHERE"
@@ -1031,12 +1040,15 @@ func (s *SqlPostStore) AnalyticsPostCountsByDay(teamId string) (model.AnalyticsR
end := utils.MillisFromTime(utils.EndOfDay(utils.Yesterday())) end := utils.MillisFromTime(utils.EndOfDay(utils.Yesterday()))
start := utils.MillisFromTime(utils.StartOfDay(utils.Yesterday().AddDate(0, 0, -31))) start := utils.MillisFromTime(utils.StartOfDay(utils.Yesterday().AddDate(0, 0, -31)))
if options.YesterdayOnly {
start = utils.MillisFromTime(utils.StartOfDay(utils.Yesterday().AddDate(0, 0, -1)))
}
var rows model.AnalyticsRows var rows model.AnalyticsRows
_, err := s.GetReplica().Select( _, err := s.GetReplica().Select(
&rows, &rows,
query, query,
map[string]interface{}{"TeamId": teamId, "StartTime": start, "EndTime": end}) map[string]interface{}{"TeamId": options.TeamId, "StartTime": start, "EndTime": end})
if err != nil { if err != nil {
return nil, model.NewAppError("SqlPostStore.AnalyticsPostCountsByDay", "store.sql_post.analytics_posts_count_by_day.app_error", nil, err.Error(), http.StatusInternalServerError) return nil, model.NewAppError("SqlPostStore.AnalyticsPostCountsByDay", "store.sql_post.analytics_posts_count_by_day.app_error", nil, err.Error(), http.StatusInternalServerError)
} }

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

@@ -229,7 +229,7 @@ type PostStore interface {
GetEtag(channelId string, allowFromCache bool) string GetEtag(channelId string, allowFromCache bool) string
Search(teamId string, userId string, params *model.SearchParams) StoreChannel Search(teamId string, userId string, params *model.SearchParams) StoreChannel
AnalyticsUserCountsWithPostsByDay(teamId string) (model.AnalyticsRows, *model.AppError) AnalyticsUserCountsWithPostsByDay(teamId string) (model.AnalyticsRows, *model.AppError)
AnalyticsPostCountsByDay(teamId string) (model.AnalyticsRows, *model.AppError) AnalyticsPostCountsByDay(options *model.AnalyticsPostCountsOptions) (model.AnalyticsRows, *model.AppError)
AnalyticsPostCount(teamId string, mustHaveFile bool, mustHaveHashtag bool) (int64, *model.AppError) AnalyticsPostCount(teamId string, mustHaveFile bool, mustHaveHashtag bool) (int64, *model.AppError)
ClearCaches() ClearCaches()
InvalidateLastPostTimeCache(channelId string) InvalidateLastPostTimeCache(channelId string)

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

@@ -36,13 +36,13 @@ func (_m *PostStore) AnalyticsPostCount(teamId string, mustHaveFile bool, mustHa
return r0, r1 return r0, r1
} }
// AnalyticsPostCountsByDay provides a mock function with given fields: teamId // AnalyticsPostCountsByDay provides a mock function with given fields: options
func (_m *PostStore) AnalyticsPostCountsByDay(teamId string) (model.AnalyticsRows, *model.AppError) { func (_m *PostStore) AnalyticsPostCountsByDay(options *model.AnalyticsPostCountsOptions) (model.AnalyticsRows, *model.AppError) {
ret := _m.Called(teamId) ret := _m.Called(options)
var r0 model.AnalyticsRows var r0 model.AnalyticsRows
if rf, ok := ret.Get(0).(func(string) model.AnalyticsRows); ok { if rf, ok := ret.Get(0).(func(*model.AnalyticsPostCountsOptions) model.AnalyticsRows); ok {
r0 = rf(teamId) r0 = rf(options)
} else { } else {
if ret.Get(0) != nil { if ret.Get(0) != nil {
r0 = ret.Get(0).(model.AnalyticsRows) r0 = ret.Get(0).(model.AnalyticsRows)
@@ -50,8 +50,8 @@ func (_m *PostStore) AnalyticsPostCountsByDay(teamId string) (model.AnalyticsRow
} }
var r1 *model.AppError var r1 *model.AppError
if rf, ok := ret.Get(1).(func(string) *model.AppError); ok { if rf, ok := ret.Get(1).(func(*model.AnalyticsPostCountsOptions) *model.AppError); ok {
r1 = rf(teamId) r1 = rf(options)
} else { } else {
if ret.Get(1) != nil { if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError) r1 = ret.Get(1).(*model.AppError)

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

@@ -1352,28 +1352,75 @@ func testPostCountsByDay(t *testing.T, ss store.Store) {
_, err = ss.Post().Save(o2a) _, err = ss.Post().Save(o2a)
require.Nil(t, err) require.Nil(t, err)
bot1 := &model.Bot{
Username: "username",
Description: "a bot",
OwnerId: model.NewId(),
UserId: model.NewId(),
}
_, err = ss.Bot().Save(bot1)
b1 := &model.Post{}
b1.Message = "bot message one"
b1.ChannelId = c1.Id
b1.UserId = bot1.UserId
b1.CreateAt = utils.MillisFromTime(utils.Yesterday())
_, err = ss.Post().Save(b1)
require.Nil(t, err)
b1a := &model.Post{}
b1a.Message = "bot message two"
b1a.ChannelId = c1.Id
b1a.UserId = bot1.UserId
b1a.CreateAt = utils.MillisFromTime(utils.Yesterday()) - (1000 * 60 * 60 * 24 * 2)
_, err = ss.Post().Save(b1a)
require.Nil(t, err)
time.Sleep(1 * time.Second) time.Sleep(1 * time.Second)
if r1, err := ss.Post().AnalyticsPostCountsByDay(t1.Id); err != nil { // summary of posts
// yesterday - 2 non-bot user posts, 1 bot user post
// 3 days ago - 2 non-bot user posts, 1 bot user post
// last 31 days, all users (including bots)
postCountsOptions := &model.AnalyticsPostCountsOptions{TeamId: t1.Id, BotsOnly: false, YesterdayOnly: false}
if r1, err := ss.Post().AnalyticsPostCountsByDay(postCountsOptions); err != nil {
t.Fatal(err) t.Fatal(err)
} else { } else {
row1 := r1[0] assert.Equal(t, float64(3), r1[0].Value)
if row1.Value != 2 { assert.Equal(t, float64(3), r1[1].Value)
t.Fatal(row1)
}
row2 := r1[1]
if row2.Value != 2 {
t.Fatal("wrong value")
}
} }
// last 31 days, bots only
postCountsOptions = &model.AnalyticsPostCountsOptions{TeamId: t1.Id, BotsOnly: true, YesterdayOnly: false}
if r1, err := ss.Post().AnalyticsPostCountsByDay(postCountsOptions); err != nil {
t.Fatal(err)
} else {
assert.Equal(t, float64(1), r1[0].Value)
assert.Equal(t, float64(1), r1[1].Value)
}
// yesterday only, all users (including bots)
postCountsOptions = &model.AnalyticsPostCountsOptions{TeamId: t1.Id, BotsOnly: false, YesterdayOnly: true}
if r1, err := ss.Post().AnalyticsPostCountsByDay(postCountsOptions); err != nil {
t.Fatal(err)
} else {
assert.Equal(t, float64(3), r1[0].Value)
}
// yesterday only, bots only
postCountsOptions = &model.AnalyticsPostCountsOptions{TeamId: t1.Id, BotsOnly: true, YesterdayOnly: true}
if r1, err := ss.Post().AnalyticsPostCountsByDay(postCountsOptions); err != nil {
t.Fatal(err)
} else {
assert.Equal(t, float64(1), r1[0].Value)
}
// total posts
if r1, err := ss.Post().AnalyticsPostCount(t1.Id, false, false); err != nil { if r1, err := ss.Post().AnalyticsPostCount(t1.Id, false, false); err != nil {
t.Fatal(err) t.Fatal(err)
} else { } else {
if r1 != 4 { assert.Equal(t, int64(6), r1)
t.Fatal("wrong value")
}
} }
} }