MM-10272: Add a count for pinned posts header icon (#11840)
Этот коммит содержится в:
коммит произвёл
Ben Schumacher
родитель
5a477a617a
Коммит
b9a3c2e90e
@@ -527,7 +527,13 @@ func getChannelStats(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
stats := model.ChannelStats{ChannelId: c.Params.ChannelId, MemberCount: memberCount, GuestCount: guestCount}
|
||||
pinnedPostCount, err := c.App.GetChannelPinnedPostCount(c.Params.ChannelId)
|
||||
if err != nil {
|
||||
c.Err = err
|
||||
return
|
||||
}
|
||||
|
||||
stats := model.ChannelStats{ChannelId: c.Params.ChannelId, MemberCount: memberCount, GuestCount: guestCount, PinnedPostCount: pinnedPostCount}
|
||||
w.Write([]byte(stats.ToJson()))
|
||||
}
|
||||
|
||||
|
||||
@@ -1849,6 +1849,16 @@ func TestGetChannelStats(t *testing.T) {
|
||||
t.Fatal("couldnt't get extra info")
|
||||
} else if stats.MemberCount != 1 {
|
||||
t.Fatal("got incorrect member count")
|
||||
} else if stats.PinnedPostCount != 0 {
|
||||
t.Fatal("got incorrect pinned post count")
|
||||
}
|
||||
|
||||
th.CreatePinnedPostWithClient(th.Client, channel)
|
||||
stats, resp = Client.GetChannelStats(channel.Id, "")
|
||||
CheckNoError(t, resp)
|
||||
|
||||
if stats.PinnedPostCount != 1 {
|
||||
t.Fatal("should have returned 1 pinned post count")
|
||||
}
|
||||
|
||||
_, resp = Client.GetChannelStats("junk", "")
|
||||
|
||||
@@ -1330,6 +1330,10 @@ func (a *App) GetChannelGuestCount(channelId string) (int64, *model.AppError) {
|
||||
return a.Srv.Store.Channel().GetGuestCount(channelId, true)
|
||||
}
|
||||
|
||||
func (a *App) GetChannelPinnedPostCount(channelId string) (int64, *model.AppError) {
|
||||
return a.Srv.Store.Channel().GetPinnedPostCount(channelId, true)
|
||||
}
|
||||
|
||||
func (a *App) GetChannelCounts(teamId string, userId string) (*model.ChannelCounts, *model.AppError) {
|
||||
return a.Srv.Store.Channel().GetChannelCounts(teamId, userId)
|
||||
}
|
||||
|
||||
@@ -289,6 +289,7 @@ func (a *App) InvalidateCacheForChannelPosts(channelId string) {
|
||||
|
||||
func (a *App) InvalidateCacheForChannelPostsSkipClusterSend(channelId string) {
|
||||
a.Srv.Store.Post().InvalidateLastPostTimeCache(channelId)
|
||||
a.Srv.Store.Channel().InvalidatePinnedPostCount(channelId)
|
||||
}
|
||||
|
||||
func (a *App) InvalidateCacheForUser(userId string) {
|
||||
|
||||
@@ -5658,6 +5658,10 @@
|
||||
"id": "store.sql_channel.get_more_channels.get.app_error",
|
||||
"translation": "Unable to get the channels"
|
||||
},
|
||||
{
|
||||
"id": "store.sql_channel.get_pinnedpost_count.app_error",
|
||||
"translation": "Unable to get the channel pinned post count"
|
||||
},
|
||||
{
|
||||
"id": "store.sql_channel.get_public_channels.get.app_error",
|
||||
"translation": "Unable to get public channels"
|
||||
|
||||
@@ -9,9 +9,10 @@ import (
|
||||
)
|
||||
|
||||
type ChannelStats struct {
|
||||
ChannelId string `json:"channel_id"`
|
||||
MemberCount int64 `json:"member_count"`
|
||||
GuestCount int64 `json:"guest_count"`
|
||||
ChannelId string `json:"channel_id"`
|
||||
MemberCount int64 `json:"member_count"`
|
||||
GuestCount int64 `json:"guest_count"`
|
||||
PinnedPostCount int64 `json:"pinnedpost_count"`
|
||||
}
|
||||
|
||||
func (o *ChannelStats) ToJson() string {
|
||||
|
||||
@@ -35,6 +35,9 @@ const (
|
||||
CHANNEL_GUESTS_COUNTS_CACHE_SIZE = model.CHANNEL_CACHE_SIZE
|
||||
CHANNEL_GUESTS_COUNTS_CACHE_SEC = 1800 // 30 mins
|
||||
|
||||
CHANNEL_PINNEDPOSTS_COUNTS_CACHE_SIZE = model.CHANNEL_CACHE_SIZE
|
||||
CHANNEL_PINNEDPOSTS_COUNTS_CACHE_SEC = 1800 // 30 mins
|
||||
|
||||
CHANNEL_CACHE_SEC = 900 // 15 mins
|
||||
)
|
||||
|
||||
@@ -281,6 +284,7 @@ type publicChannel struct {
|
||||
}
|
||||
|
||||
var channelMemberCountsCache = utils.NewLru(CHANNEL_MEMBERS_COUNTS_CACHE_SIZE)
|
||||
var channelPinnedPostCountsCache = utils.NewLru(CHANNEL_PINNEDPOSTS_COUNTS_CACHE_SIZE)
|
||||
var channelGuestCountsCache = utils.NewLru(CHANNEL_GUESTS_COUNTS_CACHE_SIZE)
|
||||
var allChannelMembersForUserCache = utils.NewLru(ALL_CHANNEL_MEMBERS_FOR_USER_CACHE_SIZE)
|
||||
var allChannelMembersNotifyPropsForChannelCache = utils.NewLru(ALL_CHANNEL_MEMBERS_NOTIFY_PROPS_FOR_CHANNEL_CACHE_SIZE)
|
||||
@@ -289,6 +293,7 @@ var channelByNameCache = utils.NewLru(model.CHANNEL_CACHE_SIZE)
|
||||
|
||||
func (s SqlChannelStore) ClearCaches() {
|
||||
channelMemberCountsCache.Purge()
|
||||
channelPinnedPostCountsCache.Purge()
|
||||
channelGuestCountsCache.Purge()
|
||||
allChannelMembersForUserCache.Purge()
|
||||
allChannelMembersNotifyPropsForChannelCache.Purge()
|
||||
@@ -297,6 +302,7 @@ func (s SqlChannelStore) ClearCaches() {
|
||||
|
||||
if s.metrics != nil {
|
||||
s.metrics.IncrementMemCacheInvalidationCounter("Channel Member Counts - Purge")
|
||||
s.metrics.IncrementMemCacheInvalidationCounter("Channel Pinned Post Counts - Purge")
|
||||
s.metrics.IncrementMemCacheInvalidationCounter("All Channel Members for User - Purge")
|
||||
s.metrics.IncrementMemCacheInvalidationCounter("All Channel Members Notify Props for Channel - Purge")
|
||||
s.metrics.IncrementMemCacheInvalidationCounter("Channel - Purge")
|
||||
@@ -1626,6 +1632,66 @@ func (s SqlChannelStore) GetMemberCount(channelId string, allowFromCache bool) (
|
||||
return count, nil
|
||||
}
|
||||
|
||||
func (s SqlChannelStore) InvalidatePinnedPostCount(channelId string) {
|
||||
channelPinnedPostCountsCache.Remove(channelId)
|
||||
if s.metrics != nil {
|
||||
s.metrics.IncrementMemCacheInvalidationCounter("Channel Pinned Post Counts - Remove by ChannelId")
|
||||
}
|
||||
}
|
||||
|
||||
func (s SqlChannelStore) GetPinnedPostCountFromCache(channelId string) int64 {
|
||||
if cacheItem, ok := channelPinnedPostCountsCache.Get(channelId); ok {
|
||||
if s.metrics != nil {
|
||||
s.metrics.IncrementMemCacheHitCounter("Channel Pinned Post Counts")
|
||||
}
|
||||
return cacheItem.(int64)
|
||||
}
|
||||
|
||||
if s.metrics != nil {
|
||||
s.metrics.IncrementMemCacheMissCounter("Channel Pinned Post Counts")
|
||||
}
|
||||
|
||||
count, err := s.GetPinnedPostCount(channelId, true)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
return count
|
||||
}
|
||||
|
||||
func (s SqlChannelStore) GetPinnedPostCount(channelId string, allowFromCache bool) (int64, *model.AppError) {
|
||||
if allowFromCache {
|
||||
if cacheItem, ok := channelPinnedPostCountsCache.Get(channelId); ok {
|
||||
if s.metrics != nil {
|
||||
s.metrics.IncrementMemCacheHitCounter("Channel Pinned Post Counts")
|
||||
}
|
||||
return cacheItem.(int64), nil
|
||||
}
|
||||
}
|
||||
|
||||
if s.metrics != nil {
|
||||
s.metrics.IncrementMemCacheMissCounter("Channel Pinned Post Counts")
|
||||
}
|
||||
|
||||
count, err := s.GetReplica().SelectInt(`
|
||||
SELECT count(*)
|
||||
FROM Posts
|
||||
WHERE
|
||||
IsPinned = true
|
||||
AND ChannelId = :ChannelId
|
||||
AND DeleteAt = 0`, map[string]interface{}{"ChannelId": channelId})
|
||||
|
||||
if err != nil {
|
||||
return 0, model.NewAppError("SqlChannelStore.GetPinnedPostCount", "store.sql_channel.get_pinnedpost_count.app_error", nil, "channel_id="+channelId+", "+err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
if allowFromCache {
|
||||
channelPinnedPostCountsCache.AddWithExpiresInSecs(channelId, count, CHANNEL_PINNEDPOSTS_COUNTS_CACHE_SEC)
|
||||
}
|
||||
|
||||
return count, nil
|
||||
}
|
||||
|
||||
func (s SqlChannelStore) InvalidateGuestCount(channelId string) {
|
||||
channelGuestCountsCache.Remove(channelId)
|
||||
if s.metrics != nil {
|
||||
|
||||
@@ -148,6 +148,9 @@ type ChannelStore interface {
|
||||
InvalidateMemberCount(channelId string)
|
||||
GetMemberCountFromCache(channelId string) int64
|
||||
GetMemberCount(channelId string, allowFromCache bool) (int64, *model.AppError)
|
||||
InvalidatePinnedPostCount(channelId string)
|
||||
GetPinnedPostCountFromCache(channelId string) int64
|
||||
GetPinnedPostCount(channelId string, allowFromCache bool) (int64, *model.AppError)
|
||||
InvalidateGuestCount(channelId string)
|
||||
GetGuestCountFromCache(channelId string) int64
|
||||
GetGuestCount(channelId string, allowFromCache bool) (int64, *model.AppError)
|
||||
|
||||
@@ -75,6 +75,7 @@ func TestChannelStore(t *testing.T, ss store.Store, s SqlSupplier) {
|
||||
t.Run("SearchGroupChannels", func(t *testing.T) { testChannelStoreSearchGroupChannels(t, ss) })
|
||||
t.Run("AnalyticsDeletedTypeCount", func(t *testing.T) { testChannelStoreAnalyticsDeletedTypeCount(t, ss) })
|
||||
t.Run("GetPinnedPosts", func(t *testing.T) { testChannelStoreGetPinnedPosts(t, ss) })
|
||||
t.Run("GetPinnedPostCount", func(t *testing.T) { testChannelStoreGetPinnedPostCount(t, ss) })
|
||||
t.Run("MaxChannelsPerTeam", func(t *testing.T) { testChannelStoreMaxChannelsPerTeam(t, ss) })
|
||||
t.Run("GetChannelsByScheme", func(t *testing.T) { testChannelStoreGetChannelsByScheme(t, ss) })
|
||||
t.Run("MigrateChannelMembers", func(t *testing.T) { testChannelStoreMigrateChannelMembers(t, ss) })
|
||||
@@ -3379,6 +3380,78 @@ func testChannelStoreGetPinnedPosts(t *testing.T, ss store.Store) {
|
||||
}
|
||||
}
|
||||
|
||||
func testChannelStoreGetPinnedPostCount(t *testing.T, ss store.Store) {
|
||||
ch1 := &model.Channel{
|
||||
TeamId: model.NewId(),
|
||||
DisplayName: "Name",
|
||||
Name: "zz" + model.NewId() + "b",
|
||||
Type: model.CHANNEL_OPEN,
|
||||
}
|
||||
|
||||
o1, err := ss.Channel().Save(ch1, -1)
|
||||
require.Nil(t, err)
|
||||
|
||||
_, err = ss.Post().Save(&model.Post{
|
||||
UserId: model.NewId(),
|
||||
ChannelId: o1.Id,
|
||||
Message: "test",
|
||||
IsPinned: true,
|
||||
})
|
||||
require.Nil(t, err)
|
||||
|
||||
_, err = ss.Post().Save(&model.Post{
|
||||
UserId: model.NewId(),
|
||||
ChannelId: o1.Id,
|
||||
Message: "test",
|
||||
IsPinned: true,
|
||||
})
|
||||
require.Nil(t, err)
|
||||
|
||||
if count, errGet := ss.Channel().GetPinnedPostCount(o1.Id, true); errGet != nil {
|
||||
t.Fatal(errGet)
|
||||
} else if count != 2 {
|
||||
t.Fatal("didn't return right count")
|
||||
}
|
||||
|
||||
if ss.Channel().GetPinnedPostCountFromCache(o1.Id) != 2 {
|
||||
t.Fatal("should have saved 2 pinned post count ")
|
||||
}
|
||||
|
||||
ch2 := &model.Channel{
|
||||
TeamId: model.NewId(),
|
||||
DisplayName: "Name",
|
||||
Name: "zz" + model.NewId() + "b",
|
||||
Type: model.CHANNEL_OPEN,
|
||||
}
|
||||
|
||||
o2, err := ss.Channel().Save(ch2, -1)
|
||||
require.Nil(t, err)
|
||||
|
||||
_, err = ss.Post().Save(&model.Post{
|
||||
UserId: model.NewId(),
|
||||
ChannelId: o2.Id,
|
||||
Message: "test",
|
||||
})
|
||||
require.Nil(t, err)
|
||||
|
||||
_, err = ss.Post().Save(&model.Post{
|
||||
UserId: model.NewId(),
|
||||
ChannelId: o2.Id,
|
||||
Message: "test",
|
||||
})
|
||||
require.Nil(t, err)
|
||||
|
||||
if count, errGet := ss.Channel().GetPinnedPostCount(o2.Id, true); errGet != nil {
|
||||
t.Fatal(errGet)
|
||||
} else if count != 0 {
|
||||
t.Fatal("should return 0")
|
||||
}
|
||||
|
||||
if ss.Channel().GetPinnedPostCountFromCache(o2.Id) != 0 {
|
||||
t.Fatal("should have saved 0 pinned post count ")
|
||||
}
|
||||
}
|
||||
|
||||
func testChannelStoreMaxChannelsPerTeam(t *testing.T, ss store.Store) {
|
||||
channel := &model.Channel{
|
||||
TeamId: model.NewId(),
|
||||
|
||||
@@ -993,6 +993,43 @@ func (_m *ChannelStore) GetMoreChannels(teamId string, userId string, offset int
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetPinnedPostCount provides a mock function with given fields: channelId, allowFromCache
|
||||
func (_m *ChannelStore) GetPinnedPostCount(channelId string, allowFromCache bool) (int64, *model.AppError) {
|
||||
ret := _m.Called(channelId, allowFromCache)
|
||||
|
||||
var r0 int64
|
||||
if rf, ok := ret.Get(0).(func(string, bool) int64); ok {
|
||||
r0 = rf(channelId, allowFromCache)
|
||||
} else {
|
||||
r0 = ret.Get(0).(int64)
|
||||
}
|
||||
|
||||
var r1 *model.AppError
|
||||
if rf, ok := ret.Get(1).(func(string, bool) *model.AppError); ok {
|
||||
r1 = rf(channelId, allowFromCache)
|
||||
} else {
|
||||
if ret.Get(1) != nil {
|
||||
r1 = ret.Get(1).(*model.AppError)
|
||||
}
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetPinnedPostCountFromCache provides a mock function with given fields: channelId
|
||||
func (_m *ChannelStore) GetPinnedPostCountFromCache(channelId string) int64 {
|
||||
ret := _m.Called(channelId)
|
||||
|
||||
var r0 int64
|
||||
if rf, ok := ret.Get(0).(func(string) int64); ok {
|
||||
r0 = rf(channelId)
|
||||
} else {
|
||||
r0 = ret.Get(0).(int64)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// GetPinnedPosts provides a mock function with given fields: channelId
|
||||
func (_m *ChannelStore) GetPinnedPosts(channelId string) (*model.PostList, *model.AppError) {
|
||||
ret := _m.Called(channelId)
|
||||
@@ -1139,6 +1176,11 @@ func (_m *ChannelStore) InvalidateMemberCount(channelId string) {
|
||||
_m.Called(channelId)
|
||||
}
|
||||
|
||||
// InvalidatePinnedPostCount provides a mock function with given fields: channelId
|
||||
func (_m *ChannelStore) InvalidatePinnedPostCount(channelId string) {
|
||||
_m.Called(channelId)
|
||||
}
|
||||
|
||||
// IsUserInChannelUseCache provides a mock function with given fields: userId, channelId
|
||||
func (_m *ChannelStore) IsUserInChannelUseCache(userId string, channelId string) bool {
|
||||
ret := _m.Called(userId, channelId)
|
||||
|
||||
@@ -1382,6 +1382,23 @@ func (s *TimerLayerChannelStore) InvalidateMemberCount(channelId string) {
|
||||
return
|
||||
}
|
||||
|
||||
func (s *TimerLayerChannelStore) InvalidatePinnedPostCount(channelId string) {
|
||||
start := timemodule.Now()
|
||||
|
||||
s.ChannelStore.InvalidatePinnedPostCount(channelId)
|
||||
|
||||
t := timemodule.Now()
|
||||
elapsed := t.Sub(start)
|
||||
if s.Root.Metrics != nil {
|
||||
success := "false"
|
||||
if true {
|
||||
success = "true"
|
||||
}
|
||||
s.Root.Metrics.ObserveStoreMethodDuration("ChannelStore.InvalidatePinnedPostCount", success, float64(elapsed))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *TimerLayerChannelStore) IsUserInChannelUseCache(userId string, channelId string) bool {
|
||||
start := timemodule.Now()
|
||||
|
||||
|
||||
Ссылка в новой задаче
Block a user