MM-34758 Collapsed Reply Threads without mobile support (#17424)
Summary added support for legacy clients accessing server added collapsed_threads_supported param to viewChannel API and setPostUnread API Ticket Link https://mattermost.atlassian.net/browse/MM-34758 Related Webapp PR mattermost/mattermost-webapp#7933
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
ebed0c67f7
Коммит
46649292f8
@@ -2176,7 +2176,7 @@ func (s *OpenTracingLayerChannelStore) UpdateLastViewedAt(channelIds []string, u
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (s *OpenTracingLayerChannelStore) UpdateLastViewedAtPost(unreadPost *model.Post, userID string, mentionCount int, mentionCountRoot int, updateThreads bool) (*model.ChannelUnreadAt, error) {
|
||||
func (s *OpenTracingLayerChannelStore) UpdateLastViewedAtPost(unreadPost *model.Post, userID string, mentionCount int, mentionCountRoot int, updateThreads bool, setUnreadCountRoot bool) (*model.ChannelUnreadAt, error) {
|
||||
origCtx := s.Root.Store.Context()
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.UpdateLastViewedAtPost")
|
||||
s.Root.Store.SetContext(newCtx)
|
||||
@@ -2185,7 +2185,7 @@ func (s *OpenTracingLayerChannelStore) UpdateLastViewedAtPost(unreadPost *model.
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
result, err := s.ChannelStore.UpdateLastViewedAtPost(unreadPost, userID, mentionCount, mentionCountRoot, updateThreads)
|
||||
result, err := s.ChannelStore.UpdateLastViewedAtPost(unreadPost, userID, mentionCount, mentionCountRoot, updateThreads, setUnreadCountRoot)
|
||||
if err != nil {
|
||||
span.LogFields(spanlog.Error(err))
|
||||
ext.Error.Set(span, true)
|
||||
@@ -8938,6 +8938,24 @@ func (s *OpenTracingLayerThreadStore) MarkAllAsRead(userID string, teamID string
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *OpenTracingLayerThreadStore) MarkAllAsReadInChannels(userID string, channelIDs []string) error {
|
||||
origCtx := s.Root.Store.Context()
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ThreadStore.MarkAllAsReadInChannels")
|
||||
s.Root.Store.SetContext(newCtx)
|
||||
defer func() {
|
||||
s.Root.Store.SetContext(origCtx)
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
err := s.ThreadStore.MarkAllAsReadInChannels(userID, channelIDs)
|
||||
if err != nil {
|
||||
span.LogFields(spanlog.Error(err))
|
||||
ext.Error.Set(span, true)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *OpenTracingLayerThreadStore) MarkAsRead(userID string, threadID string, timestamp int64) error {
|
||||
origCtx := s.Root.Store.Context()
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ThreadStore.MarkAsRead")
|
||||
|
||||
@@ -2308,11 +2308,11 @@ func (s *RetryLayerChannelStore) UpdateLastViewedAt(channelIds []string, userID
|
||||
|
||||
}
|
||||
|
||||
func (s *RetryLayerChannelStore) UpdateLastViewedAtPost(unreadPost *model.Post, userID string, mentionCount int, mentionCountRoot int, updateThreads bool) (*model.ChannelUnreadAt, error) {
|
||||
func (s *RetryLayerChannelStore) UpdateLastViewedAtPost(unreadPost *model.Post, userID string, mentionCount int, mentionCountRoot int, updateThreads bool, setUnreadCountRoot bool) (*model.ChannelUnreadAt, error) {
|
||||
|
||||
tries := 0
|
||||
for {
|
||||
result, err := s.ChannelStore.UpdateLastViewedAtPost(unreadPost, userID, mentionCount, mentionCountRoot, updateThreads)
|
||||
result, err := s.ChannelStore.UpdateLastViewedAtPost(unreadPost, userID, mentionCount, mentionCountRoot, updateThreads, setUnreadCountRoot)
|
||||
if err == nil {
|
||||
return result, nil
|
||||
}
|
||||
@@ -9728,6 +9728,26 @@ func (s *RetryLayerThreadStore) MarkAllAsRead(userID string, teamID string) erro
|
||||
|
||||
}
|
||||
|
||||
func (s *RetryLayerThreadStore) MarkAllAsReadInChannels(userID string, channelIDs []string) error {
|
||||
|
||||
tries := 0
|
||||
for {
|
||||
err := s.ThreadStore.MarkAllAsReadInChannels(userID, channelIDs)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
if !isRepeatableError(err) {
|
||||
return err
|
||||
}
|
||||
tries++
|
||||
if tries >= 3 {
|
||||
err = errors.Wrap(err, "giving up after 3 consecutive repeatable transaction failures")
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (s *RetryLayerThreadStore) MarkAsRead(userID string, threadID string, timestamp int64) error {
|
||||
|
||||
tries := 0
|
||||
|
||||
@@ -2216,7 +2216,7 @@ func (s SqlChannelStore) CountPostsAfter(channelId string, timestamp int64, user
|
||||
// UpdateLastViewedAtPost updates a ChannelMember as if the user last read the channel at the time of the given post.
|
||||
// If the provided mentionCount is -1, the given post and all posts after it are considered to be mentions. Returns
|
||||
// an updated model.ChannelUnreadAt that can be returned to the client.
|
||||
func (s SqlChannelStore) UpdateLastViewedAtPost(unreadPost *model.Post, userID string, mentionCount, mentionCountRoot int, updateThreads bool) (*model.ChannelUnreadAt, error) {
|
||||
func (s SqlChannelStore) UpdateLastViewedAtPost(unreadPost *model.Post, userID string, mentionCount, mentionCountRoot int, updateThreads bool, setUnreadCountRoot bool) (*model.ChannelUnreadAt, error) {
|
||||
var threadsToUpdate []string
|
||||
unreadDate := unreadPost.CreateAt - 1
|
||||
if updateThreads {
|
||||
@@ -2232,6 +2232,10 @@ func (s SqlChannelStore) UpdateLastViewedAtPost(unreadPost *model.Post, userID s
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !setUnreadCountRoot {
|
||||
unreadRoot = 0
|
||||
}
|
||||
|
||||
params := map[string]interface{}{
|
||||
"mentions": mentionCount,
|
||||
"mentionsRoot": mentionCountRoot,
|
||||
|
||||
@@ -386,7 +386,37 @@ func (s *SqlThreadStore) GetThreadForUser(userId, teamId, threadId string, exten
|
||||
|
||||
return result, nil
|
||||
}
|
||||
func (s *SqlThreadStore) MarkAllAsReadInChannels(userID string, channelIDs []string) error {
|
||||
var threadIDs []string
|
||||
|
||||
query, args, _ := s.getQueryBuilder().
|
||||
Select("ThreadMemberships.PostId").
|
||||
Join("Threads ON Threads.PostId = ThreadMemberships.PostId").
|
||||
Join("Channels ON Threads.ChannelId = Channels.Id").
|
||||
From("ThreadMemberships").
|
||||
Where(sq.Eq{"Threads.ChannelId": channelIDs}).
|
||||
Where(sq.Eq{"ThreadMemberships.UserId": userID}).
|
||||
ToSql()
|
||||
|
||||
_, err := s.GetReplica().Select(&threadIDs, query, args...)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to get thread membership with userid=%s", userID)
|
||||
}
|
||||
|
||||
timestamp := model.GetMillis()
|
||||
query, args, _ = s.getQueryBuilder().
|
||||
Update("ThreadMemberships").
|
||||
Where(sq.Eq{"PostId": threadIDs}).
|
||||
Where(sq.Eq{"UserId": userID}).
|
||||
Set("LastViewed", timestamp).
|
||||
Set("UnreadMentions", 0).
|
||||
ToSql()
|
||||
if _, err := s.GetMaster().Exec(query, args...); err != nil {
|
||||
return errors.Wrapf(err, "failed to update thread read state for user id=%s", userID)
|
||||
}
|
||||
return nil
|
||||
|
||||
}
|
||||
func (s *SqlThreadStore) MarkAllAsRead(userId, teamId string) error {
|
||||
memberships, err := s.GetMembershipsForUser(userId, teamId)
|
||||
if err != nil {
|
||||
|
||||
@@ -216,7 +216,7 @@ type ChannelStore interface {
|
||||
PermanentDeleteMembersByUser(userID string) error
|
||||
PermanentDeleteMembersByChannel(channelID string) error
|
||||
UpdateLastViewedAt(channelIds []string, userID string, updateThreads bool) (map[string]int64, error)
|
||||
UpdateLastViewedAtPost(unreadPost *model.Post, userID string, mentionCount, mentionCountRoot int, updateThreads bool) (*model.ChannelUnreadAt, error)
|
||||
UpdateLastViewedAtPost(unreadPost *model.Post, userID string, mentionCount, mentionCountRoot int, updateThreads bool, setUnreadCountRoot bool) (*model.ChannelUnreadAt, error)
|
||||
CountPostsAfter(channelID string, timestamp int64, userID string) (int, int, error)
|
||||
IncrementMentionCount(channelID string, userID string, updateThreads, isRoot bool) error
|
||||
AnalyticsTypeCount(teamID string, channelType string) (int64, error)
|
||||
@@ -288,6 +288,7 @@ type ThreadStore interface {
|
||||
GetPosts(threadID string, since int64) ([]*model.Post, error)
|
||||
|
||||
MarkAllAsRead(userID, teamID string) error
|
||||
MarkAllAsReadInChannels(userID string, channelIDs []string) error
|
||||
MarkAsRead(userID, threadID string, timestamp int64) error
|
||||
|
||||
SaveMembership(membership *model.ThreadMembership) (*model.ThreadMembership, error)
|
||||
|
||||
@@ -1861,13 +1861,13 @@ func (_m *ChannelStore) UpdateLastViewedAt(channelIds []string, userID string, u
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// UpdateLastViewedAtPost provides a mock function with given fields: unreadPost, userID, mentionCount, mentionCountRoot, updateThreads
|
||||
func (_m *ChannelStore) UpdateLastViewedAtPost(unreadPost *model.Post, userID string, mentionCount int, mentionCountRoot int, updateThreads bool) (*model.ChannelUnreadAt, error) {
|
||||
ret := _m.Called(unreadPost, userID, mentionCount, mentionCountRoot, updateThreads)
|
||||
// UpdateLastViewedAtPost provides a mock function with given fields: unreadPost, userID, mentionCount, mentionCountRoot, updateThreads, setUnreadCountRoot
|
||||
func (_m *ChannelStore) UpdateLastViewedAtPost(unreadPost *model.Post, userID string, mentionCount int, mentionCountRoot int, updateThreads bool, setUnreadCountRoot bool) (*model.ChannelUnreadAt, error) {
|
||||
ret := _m.Called(unreadPost, userID, mentionCount, mentionCountRoot, updateThreads, setUnreadCountRoot)
|
||||
|
||||
var r0 *model.ChannelUnreadAt
|
||||
if rf, ok := ret.Get(0).(func(*model.Post, string, int, int, bool) *model.ChannelUnreadAt); ok {
|
||||
r0 = rf(unreadPost, userID, mentionCount, mentionCountRoot, updateThreads)
|
||||
if rf, ok := ret.Get(0).(func(*model.Post, string, int, int, bool, bool) *model.ChannelUnreadAt); ok {
|
||||
r0 = rf(unreadPost, userID, mentionCount, mentionCountRoot, updateThreads, setUnreadCountRoot)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*model.ChannelUnreadAt)
|
||||
@@ -1875,8 +1875,8 @@ func (_m *ChannelStore) UpdateLastViewedAtPost(unreadPost *model.Post, userID st
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(*model.Post, string, int, int, bool) error); ok {
|
||||
r1 = rf(unreadPost, userID, mentionCount, mentionCountRoot, updateThreads)
|
||||
if rf, ok := ret.Get(1).(func(*model.Post, string, int, int, bool, bool) error); ok {
|
||||
r1 = rf(unreadPost, userID, mentionCount, mentionCountRoot, updateThreads, setUnreadCountRoot)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
@@ -263,6 +263,20 @@ func (_m *ThreadStore) MarkAllAsRead(userID string, teamID string) error {
|
||||
return r0
|
||||
}
|
||||
|
||||
// MarkAllAsReadInChannels provides a mock function with given fields: userID, channelIDs
|
||||
func (_m *ThreadStore) MarkAllAsReadInChannels(userID string, channelIDs []string) error {
|
||||
ret := _m.Called(userID, channelIDs)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(string, []string) error); ok {
|
||||
r0 = rf(userID, channelIDs)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// MarkAsRead provides a mock function with given fields: userID, threadID, timestamp
|
||||
func (_m *ThreadStore) MarkAsRead(userID string, threadID string, timestamp int64) error {
|
||||
ret := _m.Called(userID, threadID, timestamp)
|
||||
|
||||
@@ -243,7 +243,7 @@ func testThreadStorePopulation(t *testing.T, ss store.Store) {
|
||||
_, err := ss.Thread().UpdateMembership(m)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = ss.Channel().UpdateLastViewedAtPost(newPosts[0], newPosts[0].UserId, 0, 0, true)
|
||||
_, err = ss.Channel().UpdateLastViewedAtPost(newPosts[0], newPosts[0].UserId, 0, 0, true, true)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Eventually(t, func() bool {
|
||||
@@ -325,7 +325,7 @@ func testThreadStorePopulation(t *testing.T, ss store.Store) {
|
||||
_, err := ss.Thread().UpdateMembership(m)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = ss.Channel().UpdateLastViewedAtPost(newPosts[0], newPosts[0].UserId, 0, 0, true)
|
||||
_, err = ss.Channel().UpdateLastViewedAtPost(newPosts[0], newPosts[0].UserId, 0, 0, true, true)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Eventually(t, func() bool {
|
||||
|
||||
@@ -2014,10 +2014,10 @@ func (s *TimerLayerChannelStore) UpdateLastViewedAt(channelIds []string, userID
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (s *TimerLayerChannelStore) UpdateLastViewedAtPost(unreadPost *model.Post, userID string, mentionCount int, mentionCountRoot int, updateThreads bool) (*model.ChannelUnreadAt, error) {
|
||||
func (s *TimerLayerChannelStore) UpdateLastViewedAtPost(unreadPost *model.Post, userID string, mentionCount int, mentionCountRoot int, updateThreads bool, setUnreadCountRoot bool) (*model.ChannelUnreadAt, error) {
|
||||
start := timemodule.Now()
|
||||
|
||||
result, err := s.ChannelStore.UpdateLastViewedAtPost(unreadPost, userID, mentionCount, mentionCountRoot, updateThreads)
|
||||
result, err := s.ChannelStore.UpdateLastViewedAtPost(unreadPost, userID, mentionCount, mentionCountRoot, updateThreads, setUnreadCountRoot)
|
||||
|
||||
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
|
||||
if s.Root.Metrics != nil {
|
||||
@@ -8054,6 +8054,22 @@ func (s *TimerLayerThreadStore) MarkAllAsRead(userID string, teamID string) erro
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *TimerLayerThreadStore) MarkAllAsReadInChannels(userID string, channelIDs []string) error {
|
||||
start := timemodule.Now()
|
||||
|
||||
err := s.ThreadStore.MarkAllAsReadInChannels(userID, channelIDs)
|
||||
|
||||
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
|
||||
if s.Root.Metrics != nil {
|
||||
success := "false"
|
||||
if err == nil {
|
||||
success = "true"
|
||||
}
|
||||
s.Root.Metrics.ObserveStoreMethodDuration("ThreadStore.MarkAllAsReadInChannels", success, elapsed)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *TimerLayerThreadStore) MarkAsRead(userID string, threadID string, timestamp int64) error {
|
||||
start := timemodule.Now()
|
||||
|
||||
|
||||
Ссылка в новой задаче
Block a user