[MM-41998] Channel Info RHS: display number of files for a channel (#19822)
Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
Этот коммит содержится в:
@@ -709,6 +709,33 @@ func (th *TestHelper) CreateMessagePost(message string) *model.Post {
|
|||||||
return th.CreateMessagePostWithClient(th.Client, th.BasicChannel, message)
|
return th.CreateMessagePostWithClient(th.Client, th.BasicChannel, message)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (th *TestHelper) CreatePostWithFiles(files ...*model.FileInfo) *model.Post {
|
||||||
|
return th.CreatePostWithFilesWithClient(th.Client, th.BasicChannel, files...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (th *TestHelper) CreatePostInChannelWithFiles(channel *model.Channel, files ...*model.FileInfo) *model.Post {
|
||||||
|
return th.CreatePostWithFilesWithClient(th.Client, channel, files...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (th *TestHelper) CreatePostWithFilesWithClient(client *model.Client4, channel *model.Channel, files ...*model.FileInfo) *model.Post {
|
||||||
|
var fileIds model.StringArray
|
||||||
|
for i := range files {
|
||||||
|
fileIds = append(fileIds, files[i].Id)
|
||||||
|
}
|
||||||
|
|
||||||
|
post := &model.Post{
|
||||||
|
ChannelId: channel.Id,
|
||||||
|
Message: "message_" + model.NewId(),
|
||||||
|
FileIds: fileIds,
|
||||||
|
}
|
||||||
|
|
||||||
|
rpost, _, err := client.CreatePost(post)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return rpost
|
||||||
|
}
|
||||||
|
|
||||||
func (th *TestHelper) CreatePostWithClient(client *model.Client4, channel *model.Channel) *model.Post {
|
func (th *TestHelper) CreatePostWithClient(client *model.Client4, channel *model.Channel) *model.Post {
|
||||||
id := model.NewId()
|
id := model.NewId()
|
||||||
|
|
||||||
|
|||||||
@@ -642,11 +642,18 @@ func getChannelStats(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
filesCount, err := c.App.GetChannelFileCount(c.Params.ChannelId)
|
||||||
|
if err != nil {
|
||||||
|
c.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
stats := model.ChannelStats{
|
stats := model.ChannelStats{
|
||||||
ChannelId: c.Params.ChannelId,
|
ChannelId: c.Params.ChannelId,
|
||||||
MemberCount: memberCount,
|
MemberCount: memberCount,
|
||||||
GuestCount: guestCount,
|
GuestCount: guestCount,
|
||||||
PinnedPostCount: pinnedPostCount,
|
PinnedPostCount: pinnedPostCount,
|
||||||
|
FilesCount: filesCount,
|
||||||
}
|
}
|
||||||
if err := json.NewEncoder(w).Encode(stats); err != nil {
|
if err := json.NewEncoder(w).Encode(stats); err != nil {
|
||||||
mlog.Warn("Error while writing response", mlog.Err(err))
|
mlog.Warn("Error while writing response", mlog.Err(err))
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import (
|
|||||||
"github.com/mattermost/mattermost-server/v6/model"
|
"github.com/mattermost/mattermost-server/v6/model"
|
||||||
"github.com/mattermost/mattermost-server/v6/plugin/plugintest/mock"
|
"github.com/mattermost/mattermost-server/v6/plugin/plugintest/mock"
|
||||||
"github.com/mattermost/mattermost-server/v6/store/storetest/mocks"
|
"github.com/mattermost/mattermost-server/v6/store/storetest/mocks"
|
||||||
|
"github.com/mattermost/mattermost-server/v6/utils/testutils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCreateChannel(t *testing.T) {
|
func TestCreateChannel(t *testing.T) {
|
||||||
@@ -2507,12 +2508,24 @@ func TestGetChannelStats(t *testing.T) {
|
|||||||
require.Equal(t, channel.Id, stats.ChannelId, "couldn't get extra info")
|
require.Equal(t, channel.Id, stats.ChannelId, "couldn't get extra info")
|
||||||
require.Equal(t, int64(1), stats.MemberCount, "got incorrect member count")
|
require.Equal(t, int64(1), stats.MemberCount, "got incorrect member count")
|
||||||
require.Equal(t, int64(0), stats.PinnedPostCount, "got incorrect pinned post count")
|
require.Equal(t, int64(0), stats.PinnedPostCount, "got incorrect pinned post count")
|
||||||
|
require.Equal(t, int64(0), stats.FilesCount, "got incorrect file count")
|
||||||
|
|
||||||
th.CreatePinnedPostWithClient(th.Client, channel)
|
th.CreatePinnedPostWithClient(th.Client, channel)
|
||||||
stats, _, err = client.GetChannelStats(channel.Id, "")
|
stats, _, err = client.GetChannelStats(channel.Id, "")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, int64(1), stats.PinnedPostCount, "should have returned 1 pinned post count")
|
require.Equal(t, int64(1), stats.PinnedPostCount, "should have returned 1 pinned post count")
|
||||||
|
|
||||||
|
// create a post with a file
|
||||||
|
sent, err := testutils.ReadTestFile("test.png")
|
||||||
|
require.NoError(t, err)
|
||||||
|
fileResp, _, err := client.UploadFile(sent, channel.Id, "test.png")
|
||||||
|
require.NoError(t, err)
|
||||||
|
th.CreatePostInChannelWithFiles(channel, fileResp.FileInfos...)
|
||||||
|
// make sure the file count channel stats is updated
|
||||||
|
stats, _, err = client.GetChannelStats(channel.Id, "")
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, int64(1), stats.FilesCount, "should have returned 1 file count")
|
||||||
|
|
||||||
_, resp, err := client.GetChannelStats("junk", "")
|
_, resp, err := client.GetChannelStats("junk", "")
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
CheckBadRequestStatus(t, resp)
|
CheckBadRequestStatus(t, resp)
|
||||||
|
|||||||
@@ -561,6 +561,7 @@ type AppIface interface {
|
|||||||
GetChannelByName(channelName, teamID string, includeDeleted bool) (*model.Channel, *model.AppError)
|
GetChannelByName(channelName, teamID string, includeDeleted bool) (*model.Channel, *model.AppError)
|
||||||
GetChannelByNameForTeamName(channelName, teamName string, includeDeleted bool) (*model.Channel, *model.AppError)
|
GetChannelByNameForTeamName(channelName, teamName string, includeDeleted bool) (*model.Channel, *model.AppError)
|
||||||
GetChannelCounts(teamID string, userID string) (*model.ChannelCounts, *model.AppError)
|
GetChannelCounts(teamID string, userID string) (*model.ChannelCounts, *model.AppError)
|
||||||
|
GetChannelFileCount(channelID string) (int64, *model.AppError)
|
||||||
GetChannelGuestCount(channelID string) (int64, *model.AppError)
|
GetChannelGuestCount(channelID string) (int64, *model.AppError)
|
||||||
GetChannelMember(ctx context.Context, channelID string, userID string) (*model.ChannelMember, *model.AppError)
|
GetChannelMember(ctx context.Context, channelID string, userID string) (*model.ChannelMember, *model.AppError)
|
||||||
GetChannelMemberCount(channelID string) (int64, *model.AppError)
|
GetChannelMemberCount(channelID string) (int64, *model.AppError)
|
||||||
|
|||||||
@@ -2009,6 +2009,15 @@ func (a *App) GetChannelMemberCount(channelID string) (int64, *model.AppError) {
|
|||||||
return count, nil
|
return count, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *App) GetChannelFileCount(channelID string) (int64, *model.AppError) {
|
||||||
|
count, err := a.Srv().Store.Channel().GetFileCount(channelID)
|
||||||
|
if err != nil {
|
||||||
|
return 0, model.NewAppError("SqlChannelStore.GetFileCount", "app.channel.get_file_count.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
return count, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (a *App) GetChannelGuestCount(channelID string) (int64, *model.AppError) {
|
func (a *App) GetChannelGuestCount(channelID string) (int64, *model.AppError) {
|
||||||
count, err := a.Srv().Store.Channel().GetGuestCount(channelID, true)
|
count, err := a.Srv().Store.Channel().GetGuestCount(channelID, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -4890,6 +4890,28 @@ func (a *OpenTracingAppLayer) GetChannelCounts(teamID string, userID string) (*m
|
|||||||
return resultVar0, resultVar1
|
return resultVar0, resultVar1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *OpenTracingAppLayer) GetChannelFileCount(channelID string) (int64, *model.AppError) {
|
||||||
|
origCtx := a.ctx
|
||||||
|
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetChannelFileCount")
|
||||||
|
|
||||||
|
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.GetChannelFileCount(channelID)
|
||||||
|
|
||||||
|
if resultVar1 != nil {
|
||||||
|
span.LogFields(spanlog.Error(resultVar1))
|
||||||
|
ext.Error.Set(span, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultVar0, resultVar1
|
||||||
|
}
|
||||||
|
|
||||||
func (a *OpenTracingAppLayer) GetChannelGroupUsers(channelID string) ([]*model.User, *model.AppError) {
|
func (a *OpenTracingAppLayer) GetChannelGroupUsers(channelID string) ([]*model.User, *model.AppError) {
|
||||||
origCtx := a.ctx
|
origCtx := a.ctx
|
||||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetChannelGroupUsers")
|
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetChannelGroupUsers")
|
||||||
|
|||||||
@@ -4591,6 +4591,10 @@
|
|||||||
"id": "app.channel.get_deleted.missing.app_error",
|
"id": "app.channel.get_deleted.missing.app_error",
|
||||||
"translation": "No deleted channels exist."
|
"translation": "No deleted channels exist."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "app.channel.get_file_count.app_error",
|
||||||
|
"translation": "Unable to get the file count for the channel"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "app.channel.get_for_post.app_error",
|
"id": "app.channel.get_for_post.app_error",
|
||||||
"translation": "Unable to get the channel for the given post."
|
"translation": "Unable to get the channel for the given post."
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ type ChannelStats struct {
|
|||||||
MemberCount int64 `json:"member_count"`
|
MemberCount int64 `json:"member_count"`
|
||||||
GuestCount int64 `json:"guest_count"`
|
GuestCount int64 `json:"guest_count"`
|
||||||
PinnedPostCount int64 `json:"pinnedpost_count"`
|
PinnedPostCount int64 `json:"pinnedpost_count"`
|
||||||
|
FilesCount int64 `json:"files_count"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *ChannelStats) MemberCount_() float64 {
|
func (o *ChannelStats) MemberCount_() float64 {
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ const (
|
|||||||
ClusterEventInvalidateCacheForWebhooks ClusterEvent = "inv_webhooks"
|
ClusterEventInvalidateCacheForWebhooks ClusterEvent = "inv_webhooks"
|
||||||
ClusterEventInvalidateCacheForEmojisById ClusterEvent = "inv_emojis_by_id"
|
ClusterEventInvalidateCacheForEmojisById ClusterEvent = "inv_emojis_by_id"
|
||||||
ClusterEventInvalidateCacheForEmojisIdByName ClusterEvent = "inv_emojis_id_by_name"
|
ClusterEventInvalidateCacheForEmojisIdByName ClusterEvent = "inv_emojis_id_by_name"
|
||||||
|
ClusterEventInvalidateCacheForChannelFileCount ClusterEvent = "inv_channel_file_count"
|
||||||
ClusterEventInvalidateCacheForChannelPinnedpostsCounts ClusterEvent = "inv_channel_pinnedposts_counts"
|
ClusterEventInvalidateCacheForChannelPinnedpostsCounts ClusterEvent = "inv_channel_pinnedposts_counts"
|
||||||
ClusterEventInvalidateCacheForChannelMemberCounts ClusterEvent = "inv_channel_member_counts"
|
ClusterEventInvalidateCacheForChannelMemberCounts ClusterEvent = "inv_channel_member_counts"
|
||||||
ClusterEventInvalidateCacheForLastPosts ClusterEvent = "inv_last_posts"
|
ClusterEventInvalidateCacheForLastPosts ClusterEvent = "inv_last_posts"
|
||||||
|
|||||||
@@ -1249,6 +1249,24 @@ func (s *OpenTracingLayerChannelStore) GetDeletedByName(team_id string, name str
|
|||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *OpenTracingLayerChannelStore) GetFileCount(channelID string) (int64, error) {
|
||||||
|
origCtx := s.Root.Store.Context()
|
||||||
|
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.GetFileCount")
|
||||||
|
s.Root.Store.SetContext(newCtx)
|
||||||
|
defer func() {
|
||||||
|
s.Root.Store.SetContext(origCtx)
|
||||||
|
}()
|
||||||
|
|
||||||
|
defer span.Finish()
|
||||||
|
result, err := s.ChannelStore.GetFileCount(channelID)
|
||||||
|
if err != nil {
|
||||||
|
span.LogFields(spanlog.Error(err))
|
||||||
|
ext.Error.Set(span, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
func (s *OpenTracingLayerChannelStore) GetForPost(postID string) (*model.Channel, error) {
|
func (s *OpenTracingLayerChannelStore) GetForPost(postID string) (*model.Channel, error) {
|
||||||
origCtx := s.Root.Store.Context()
|
origCtx := s.Root.Store.Context()
|
||||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.GetForPost")
|
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.GetForPost")
|
||||||
|
|||||||
@@ -1402,6 +1402,27 @@ func (s *RetryLayerChannelStore) GetDeletedByName(team_id string, name string) (
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *RetryLayerChannelStore) GetFileCount(channelID string) (int64, error) {
|
||||||
|
|
||||||
|
tries := 0
|
||||||
|
for {
|
||||||
|
result, err := s.ChannelStore.GetFileCount(channelID)
|
||||||
|
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) GetForPost(postID string) (*model.Channel, error) {
|
func (s *RetryLayerChannelStore) GetForPost(postID string) (*model.Channel, error) {
|
||||||
|
|
||||||
tries := 0
|
tries := 0
|
||||||
|
|||||||
@@ -2188,6 +2188,25 @@ func (s SqlChannelStore) GetMemberCountFromCache(channelId string) int64 {
|
|||||||
return count
|
return count
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s SqlChannelStore) GetFileCount(channelId string) (int64, error) {
|
||||||
|
var count int64
|
||||||
|
err := s.GetReplicaX().Get(&count, `
|
||||||
|
SELECT
|
||||||
|
COUNT(*)
|
||||||
|
FROM
|
||||||
|
FileInfo
|
||||||
|
LEFT JOIN Posts as P ON FileInfo.PostId=P.Id
|
||||||
|
LEFT JOIN Channels as C on C.Id=P.ChannelId
|
||||||
|
WHERE
|
||||||
|
FileInfo.DeleteAt = 0
|
||||||
|
AND C.Id = ?`, channelId)
|
||||||
|
if err != nil {
|
||||||
|
return 0, errors.Wrapf(err, "failed to count files with channelId=%s", channelId)
|
||||||
|
}
|
||||||
|
|
||||||
|
return count, nil
|
||||||
|
}
|
||||||
|
|
||||||
//nolint:unparam
|
//nolint:unparam
|
||||||
func (s SqlChannelStore) GetMemberCount(channelId string, allowFromCache bool) (int64, error) {
|
func (s SqlChannelStore) GetMemberCount(channelId string, allowFromCache bool) (int64, error) {
|
||||||
var count int64
|
var count int64
|
||||||
|
|||||||
@@ -213,6 +213,7 @@ type ChannelStore interface {
|
|||||||
GetMemberForPost(postID string, userID string) (*model.ChannelMember, error)
|
GetMemberForPost(postID string, userID string) (*model.ChannelMember, error)
|
||||||
InvalidateMemberCount(channelID string)
|
InvalidateMemberCount(channelID string)
|
||||||
GetMemberCountFromCache(channelID string) int64
|
GetMemberCountFromCache(channelID string) int64
|
||||||
|
GetFileCount(channelID string) (int64, error)
|
||||||
GetMemberCount(channelID string, allowFromCache bool) (int64, error)
|
GetMemberCount(channelID string, allowFromCache bool) (int64, error)
|
||||||
GetMemberCountsByGroup(ctx context.Context, channelID string, includeTimezones bool) ([]*model.ChannelMemberCountByGroup, error)
|
GetMemberCountsByGroup(ctx context.Context, channelID string, includeTimezones bool) ([]*model.ChannelMemberCountByGroup, error)
|
||||||
InvalidatePinnedPostCount(channelID string)
|
InvalidatePinnedPostCount(channelID string)
|
||||||
|
|||||||
@@ -881,6 +881,27 @@ func (_m *ChannelStore) GetDeletedByName(team_id string, name string) (*model.Ch
|
|||||||
return r0, r1
|
return r0, r1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetFileCount provides a mock function with given fields: channelID
|
||||||
|
func (_m *ChannelStore) GetFileCount(channelID string) (int64, error) {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
var r1 error
|
||||||
|
if rf, ok := ret.Get(1).(func(string) error); ok {
|
||||||
|
r1 = rf(channelID)
|
||||||
|
} else {
|
||||||
|
r1 = ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
// GetForPost provides a mock function with given fields: postID
|
// GetForPost provides a mock function with given fields: postID
|
||||||
func (_m *ChannelStore) GetForPost(postID string) (*model.Channel, error) {
|
func (_m *ChannelStore) GetForPost(postID string) (*model.Channel, error) {
|
||||||
ret := _m.Called(postID)
|
ret := _m.Called(postID)
|
||||||
|
|||||||
@@ -1157,6 +1157,22 @@ func (s *TimerLayerChannelStore) GetDeletedByName(team_id string, name string) (
|
|||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *TimerLayerChannelStore) GetFileCount(channelID string) (int64, error) {
|
||||||
|
start := timemodule.Now()
|
||||||
|
|
||||||
|
result, err := s.ChannelStore.GetFileCount(channelID)
|
||||||
|
|
||||||
|
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
|
||||||
|
if s.Root.Metrics != nil {
|
||||||
|
success := "false"
|
||||||
|
if err == nil {
|
||||||
|
success = "true"
|
||||||
|
}
|
||||||
|
s.Root.Metrics.ObserveStoreMethodDuration("ChannelStore.GetFileCount", success, elapsed)
|
||||||
|
}
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
func (s *TimerLayerChannelStore) GetForPost(postID string) (*model.Channel, error) {
|
func (s *TimerLayerChannelStore) GetForPost(postID string) (*model.Channel, error) {
|
||||||
start := timemodule.Now()
|
start := timemodule.Now()
|
||||||
|
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user