MM-46410: adds urgency on mention counts (#20999)
* MM-46410: adds urgency on mention counts We have introduced priority for posts in https://github.com/mattermost/mattermost-webapp/pull/10951. We do need to color the mention badges in the webapp with a prominent color when a mention is posted in an urgent message. A thread has urgent mentions if the root post is marked as urgent, and the replies contain mentions to the user viewing the thread. This PR adds a column, urgentmentioncount, in channelmembers. Furthermore when asking for team/thread mention counts, we also return urgent mention counts for the user. Adds a new table to hold posts priorities Refactors priority out of the props and into the new table We are nilifying Metadata when post.ForPlugin(), which didn't save Priority for a post when Boards was enabled. This commit copies metadata again to the post, so metadata are reinstated. Co-authored-by: Mattermod <mattermod@users.noreply.github.com> Co-authored-by: Vishal Choudhary <vish9812@gmail.com>
Этот коммит содержится в:
@@ -37,6 +37,7 @@ type OpenTracingLayer struct {
|
||||
OAuthStore store.OAuthStore
|
||||
PluginStore store.PluginStore
|
||||
PostStore store.PostStore
|
||||
PostPriorityStore store.PostPriorityStore
|
||||
PreferenceStore store.PreferenceStore
|
||||
ProductNoticesStore store.ProductNoticesStore
|
||||
ReactionStore store.ReactionStore
|
||||
@@ -131,6 +132,10 @@ func (s *OpenTracingLayer) Post() store.PostStore {
|
||||
return s.PostStore
|
||||
}
|
||||
|
||||
func (s *OpenTracingLayer) PostPriority() store.PostPriorityStore {
|
||||
return s.PostPriorityStore
|
||||
}
|
||||
|
||||
func (s *OpenTracingLayer) Preference() store.PreferenceStore {
|
||||
return s.PreferenceStore
|
||||
}
|
||||
@@ -301,6 +306,11 @@ type OpenTracingLayerPostStore struct {
|
||||
Root *OpenTracingLayer
|
||||
}
|
||||
|
||||
type OpenTracingLayerPostPriorityStore struct {
|
||||
store.PostPriorityStore
|
||||
Root *OpenTracingLayer
|
||||
}
|
||||
|
||||
type OpenTracingLayerPreferenceStore struct {
|
||||
store.PreferenceStore
|
||||
Root *OpenTracingLayer
|
||||
@@ -702,6 +712,24 @@ func (s *OpenTracingLayerChannelStore) CountPostsAfter(channelID string, timesta
|
||||
return result, resultVar1, err
|
||||
}
|
||||
|
||||
func (s *OpenTracingLayerChannelStore) CountUrgentPostsAfter(channelID string, timestamp int64, userID string) (int, error) {
|
||||
origCtx := s.Root.Store.Context()
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.CountUrgentPostsAfter")
|
||||
s.Root.Store.SetContext(newCtx)
|
||||
defer func() {
|
||||
s.Root.Store.SetContext(origCtx)
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
result, err := s.ChannelStore.CountUrgentPostsAfter(channelID, timestamp, userID)
|
||||
if err != nil {
|
||||
span.LogFields(spanlog.Error(err))
|
||||
ext.Error.Set(span, true)
|
||||
}
|
||||
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (s *OpenTracingLayerChannelStore) CreateDirectChannel(userID *model.User, otherUserID *model.User, channelOptions ...model.ChannelOption) (*model.Channel, error) {
|
||||
origCtx := s.Root.Store.Context()
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.CreateDirectChannel")
|
||||
@@ -1867,7 +1895,7 @@ func (s *OpenTracingLayerChannelStore) GroupSyncedChannelCount() (int64, error)
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (s *OpenTracingLayerChannelStore) IncrementMentionCount(channelID string, userIDs []string, isRoot bool) error {
|
||||
func (s *OpenTracingLayerChannelStore) IncrementMentionCount(channelID string, userIDs []string, isRoot bool, isUrgent bool) error {
|
||||
origCtx := s.Root.Store.Context()
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.IncrementMentionCount")
|
||||
s.Root.Store.SetContext(newCtx)
|
||||
@@ -1876,7 +1904,7 @@ func (s *OpenTracingLayerChannelStore) IncrementMentionCount(channelID string, u
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
err := s.ChannelStore.IncrementMentionCount(channelID, userIDs, isRoot)
|
||||
err := s.ChannelStore.IncrementMentionCount(channelID, userIDs, isRoot, isUrgent)
|
||||
if err != nil {
|
||||
span.LogFields(spanlog.Error(err))
|
||||
ext.Error.Set(span, true)
|
||||
@@ -2439,7 +2467,7 @@ func (s *OpenTracingLayerChannelStore) UpdateLastViewedAt(channelIds []string, u
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (s *OpenTracingLayerChannelStore) UpdateLastViewedAtPost(unreadPost *model.Post, userID string, mentionCount int, mentionCountRoot int, setUnreadCountRoot bool) (*model.ChannelUnreadAt, error) {
|
||||
func (s *OpenTracingLayerChannelStore) UpdateLastViewedAtPost(unreadPost *model.Post, userID string, mentionCount int, mentionCountRoot int, urgentMentionCount int, 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)
|
||||
@@ -2448,7 +2476,7 @@ func (s *OpenTracingLayerChannelStore) UpdateLastViewedAtPost(unreadPost *model.
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
result, err := s.ChannelStore.UpdateLastViewedAtPost(unreadPost, userID, mentionCount, mentionCountRoot, setUnreadCountRoot)
|
||||
result, err := s.ChannelStore.UpdateLastViewedAtPost(unreadPost, userID, mentionCount, mentionCountRoot, urgentMentionCount, setUnreadCountRoot)
|
||||
if err != nil {
|
||||
span.LogFields(spanlog.Error(err))
|
||||
ext.Error.Set(span, true)
|
||||
@@ -6516,6 +6544,42 @@ func (s *OpenTracingLayerPostStore) Update(newPost *model.Post, oldPost *model.P
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (s *OpenTracingLayerPostPriorityStore) GetForPost(postId string) (*model.PostPriority, error) {
|
||||
origCtx := s.Root.Store.Context()
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "PostPriorityStore.GetForPost")
|
||||
s.Root.Store.SetContext(newCtx)
|
||||
defer func() {
|
||||
s.Root.Store.SetContext(origCtx)
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
result, err := s.PostPriorityStore.GetForPost(postId)
|
||||
if err != nil {
|
||||
span.LogFields(spanlog.Error(err))
|
||||
ext.Error.Set(span, true)
|
||||
}
|
||||
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (s *OpenTracingLayerPostPriorityStore) GetForPosts(ids []string) ([]*model.PostPriority, error) {
|
||||
origCtx := s.Root.Store.Context()
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "PostPriorityStore.GetForPosts")
|
||||
s.Root.Store.SetContext(newCtx)
|
||||
defer func() {
|
||||
s.Root.Store.SetContext(origCtx)
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
result, err := s.PostPriorityStore.GetForPosts(ids)
|
||||
if err != nil {
|
||||
span.LogFields(spanlog.Error(err))
|
||||
ext.Error.Set(span, true)
|
||||
}
|
||||
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (s *OpenTracingLayerPreferenceStore) CleanupFlagsBatch(limit int64) (int64, error) {
|
||||
origCtx := s.Root.Store.Context()
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "PreferenceStore.CleanupFlagsBatch")
|
||||
@@ -9872,7 +9936,7 @@ func (s *OpenTracingLayerThreadStore) GetMembershipsForUser(userId string, teamI
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (s *OpenTracingLayerThreadStore) GetTeamsUnreadForUser(userID string, teamIDs []string) (map[string]*model.TeamUnread, error) {
|
||||
func (s *OpenTracingLayerThreadStore) GetTeamsUnreadForUser(userID string, teamIDs []string, includeUrgentMentionCount bool) (map[string]*model.TeamUnread, error) {
|
||||
origCtx := s.Root.Store.Context()
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ThreadStore.GetTeamsUnreadForUser")
|
||||
s.Root.Store.SetContext(newCtx)
|
||||
@@ -9881,7 +9945,7 @@ func (s *OpenTracingLayerThreadStore) GetTeamsUnreadForUser(userID string, teamI
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
result, err := s.ThreadStore.GetTeamsUnreadForUser(userID, teamIDs)
|
||||
result, err := s.ThreadStore.GetTeamsUnreadForUser(userID, teamIDs, includeUrgentMentionCount)
|
||||
if err != nil {
|
||||
span.LogFields(spanlog.Error(err))
|
||||
ext.Error.Set(span, true)
|
||||
@@ -9908,7 +9972,7 @@ func (s *OpenTracingLayerThreadStore) GetThreadFollowers(threadID string, fetchO
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (s *OpenTracingLayerThreadStore) GetThreadForUser(threadMembership *model.ThreadMembership, extended bool) (*model.ThreadResponse, error) {
|
||||
func (s *OpenTracingLayerThreadStore) GetThreadForUser(threadMembership *model.ThreadMembership, extended bool, postPriorityIsEnabled bool) (*model.ThreadResponse, error) {
|
||||
origCtx := s.Root.Store.Context()
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ThreadStore.GetThreadForUser")
|
||||
s.Root.Store.SetContext(newCtx)
|
||||
@@ -9917,7 +9981,7 @@ func (s *OpenTracingLayerThreadStore) GetThreadForUser(threadMembership *model.T
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
result, err := s.ThreadStore.GetThreadForUser(threadMembership, extended)
|
||||
result, err := s.ThreadStore.GetThreadForUser(threadMembership, extended, postPriorityIsEnabled)
|
||||
if err != nil {
|
||||
span.LogFields(spanlog.Error(err))
|
||||
ext.Error.Set(span, true)
|
||||
@@ -10052,6 +10116,24 @@ func (s *OpenTracingLayerThreadStore) GetTotalUnreadThreads(userId string, teamI
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (s *OpenTracingLayerThreadStore) GetTotalUnreadUrgentMentions(userId string, teamID string, opts model.GetUserThreadsOpts) (int64, error) {
|
||||
origCtx := s.Root.Store.Context()
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ThreadStore.GetTotalUnreadUrgentMentions")
|
||||
s.Root.Store.SetContext(newCtx)
|
||||
defer func() {
|
||||
s.Root.Store.SetContext(origCtx)
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
result, err := s.ThreadStore.GetTotalUnreadUrgentMentions(userId, teamID, opts)
|
||||
if err != nil {
|
||||
span.LogFields(spanlog.Error(err))
|
||||
ext.Error.Set(span, true)
|
||||
}
|
||||
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (s *OpenTracingLayerThreadStore) MaintainMembership(userID string, postID string, opts store.ThreadMembershipOpts) (*model.ThreadMembership, error) {
|
||||
origCtx := s.Root.Store.Context()
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ThreadStore.MaintainMembership")
|
||||
@@ -12509,6 +12591,7 @@ func New(childStore store.Store, ctx context.Context) *OpenTracingLayer {
|
||||
newStore.OAuthStore = &OpenTracingLayerOAuthStore{OAuthStore: childStore.OAuth(), Root: &newStore}
|
||||
newStore.PluginStore = &OpenTracingLayerPluginStore{PluginStore: childStore.Plugin(), Root: &newStore}
|
||||
newStore.PostStore = &OpenTracingLayerPostStore{PostStore: childStore.Post(), Root: &newStore}
|
||||
newStore.PostPriorityStore = &OpenTracingLayerPostPriorityStore{PostPriorityStore: childStore.PostPriority(), Root: &newStore}
|
||||
newStore.PreferenceStore = &OpenTracingLayerPreferenceStore{PreferenceStore: childStore.Preference(), Root: &newStore}
|
||||
newStore.ProductNoticesStore = &OpenTracingLayerProductNoticesStore{ProductNoticesStore: childStore.ProductNotices(), Root: &newStore}
|
||||
newStore.ReactionStore = &OpenTracingLayerReactionStore{ReactionStore: childStore.Reaction(), Root: &newStore}
|
||||
|
||||
@@ -40,6 +40,7 @@ type RetryLayer struct {
|
||||
OAuthStore store.OAuthStore
|
||||
PluginStore store.PluginStore
|
||||
PostStore store.PostStore
|
||||
PostPriorityStore store.PostPriorityStore
|
||||
PreferenceStore store.PreferenceStore
|
||||
ProductNoticesStore store.ProductNoticesStore
|
||||
ReactionStore store.ReactionStore
|
||||
@@ -134,6 +135,10 @@ func (s *RetryLayer) Post() store.PostStore {
|
||||
return s.PostStore
|
||||
}
|
||||
|
||||
func (s *RetryLayer) PostPriority() store.PostPriorityStore {
|
||||
return s.PostPriorityStore
|
||||
}
|
||||
|
||||
func (s *RetryLayer) Preference() store.PreferenceStore {
|
||||
return s.PreferenceStore
|
||||
}
|
||||
@@ -304,6 +309,11 @@ type RetryLayerPostStore struct {
|
||||
Root *RetryLayer
|
||||
}
|
||||
|
||||
type RetryLayerPostPriorityStore struct {
|
||||
store.PostPriorityStore
|
||||
Root *RetryLayer
|
||||
}
|
||||
|
||||
type RetryLayerPreferenceStore struct {
|
||||
store.PreferenceStore
|
||||
Root *RetryLayer
|
||||
@@ -762,6 +772,27 @@ func (s *RetryLayerChannelStore) CountPostsAfter(channelID string, timestamp int
|
||||
|
||||
}
|
||||
|
||||
func (s *RetryLayerChannelStore) CountUrgentPostsAfter(channelID string, timestamp int64, userID string) (int, error) {
|
||||
|
||||
tries := 0
|
||||
for {
|
||||
result, err := s.ChannelStore.CountUrgentPostsAfter(channelID, timestamp, userID)
|
||||
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) CreateDirectChannel(userID *model.User, otherUserID *model.User, channelOptions ...model.ChannelOption) (*model.Channel, error) {
|
||||
|
||||
tries := 0
|
||||
@@ -2112,11 +2143,11 @@ func (s *RetryLayerChannelStore) GroupSyncedChannelCount() (int64, error) {
|
||||
|
||||
}
|
||||
|
||||
func (s *RetryLayerChannelStore) IncrementMentionCount(channelID string, userIDs []string, isRoot bool) error {
|
||||
func (s *RetryLayerChannelStore) IncrementMentionCount(channelID string, userIDs []string, isRoot bool, isUrgent bool) error {
|
||||
|
||||
tries := 0
|
||||
for {
|
||||
err := s.ChannelStore.IncrementMentionCount(channelID, userIDs, isRoot)
|
||||
err := s.ChannelStore.IncrementMentionCount(channelID, userIDs, isRoot, isUrgent)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
@@ -2706,11 +2737,11 @@ func (s *RetryLayerChannelStore) UpdateLastViewedAt(channelIds []string, userID
|
||||
|
||||
}
|
||||
|
||||
func (s *RetryLayerChannelStore) UpdateLastViewedAtPost(unreadPost *model.Post, userID string, mentionCount int, mentionCountRoot int, setUnreadCountRoot bool) (*model.ChannelUnreadAt, error) {
|
||||
func (s *RetryLayerChannelStore) UpdateLastViewedAtPost(unreadPost *model.Post, userID string, mentionCount int, mentionCountRoot int, urgentMentionCount int, setUnreadCountRoot bool) (*model.ChannelUnreadAt, error) {
|
||||
|
||||
tries := 0
|
||||
for {
|
||||
result, err := s.ChannelStore.UpdateLastViewedAtPost(unreadPost, userID, mentionCount, mentionCountRoot, setUnreadCountRoot)
|
||||
result, err := s.ChannelStore.UpdateLastViewedAtPost(unreadPost, userID, mentionCount, mentionCountRoot, urgentMentionCount, setUnreadCountRoot)
|
||||
if err == nil {
|
||||
return result, nil
|
||||
}
|
||||
@@ -7389,6 +7420,48 @@ func (s *RetryLayerPostStore) Update(newPost *model.Post, oldPost *model.Post) (
|
||||
|
||||
}
|
||||
|
||||
func (s *RetryLayerPostPriorityStore) GetForPost(postId string) (*model.PostPriority, error) {
|
||||
|
||||
tries := 0
|
||||
for {
|
||||
result, err := s.PostPriorityStore.GetForPost(postId)
|
||||
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 *RetryLayerPostPriorityStore) GetForPosts(ids []string) ([]*model.PostPriority, error) {
|
||||
|
||||
tries := 0
|
||||
for {
|
||||
result, err := s.PostPriorityStore.GetForPosts(ids)
|
||||
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 *RetryLayerPreferenceStore) CleanupFlagsBatch(limit int64) (int64, error) {
|
||||
|
||||
tries := 0
|
||||
@@ -11286,11 +11359,11 @@ func (s *RetryLayerThreadStore) GetMembershipsForUser(userId string, teamID stri
|
||||
|
||||
}
|
||||
|
||||
func (s *RetryLayerThreadStore) GetTeamsUnreadForUser(userID string, teamIDs []string) (map[string]*model.TeamUnread, error) {
|
||||
func (s *RetryLayerThreadStore) GetTeamsUnreadForUser(userID string, teamIDs []string, includeUrgentMentionCount bool) (map[string]*model.TeamUnread, error) {
|
||||
|
||||
tries := 0
|
||||
for {
|
||||
result, err := s.ThreadStore.GetTeamsUnreadForUser(userID, teamIDs)
|
||||
result, err := s.ThreadStore.GetTeamsUnreadForUser(userID, teamIDs, includeUrgentMentionCount)
|
||||
if err == nil {
|
||||
return result, nil
|
||||
}
|
||||
@@ -11328,11 +11401,11 @@ func (s *RetryLayerThreadStore) GetThreadFollowers(threadID string, fetchOnlyAct
|
||||
|
||||
}
|
||||
|
||||
func (s *RetryLayerThreadStore) GetThreadForUser(threadMembership *model.ThreadMembership, extended bool) (*model.ThreadResponse, error) {
|
||||
func (s *RetryLayerThreadStore) GetThreadForUser(threadMembership *model.ThreadMembership, extended bool, postPriorityIsEnabled bool) (*model.ThreadResponse, error) {
|
||||
|
||||
tries := 0
|
||||
for {
|
||||
result, err := s.ThreadStore.GetThreadForUser(threadMembership, extended)
|
||||
result, err := s.ThreadStore.GetThreadForUser(threadMembership, extended, postPriorityIsEnabled)
|
||||
if err == nil {
|
||||
return result, nil
|
||||
}
|
||||
@@ -11496,6 +11569,27 @@ func (s *RetryLayerThreadStore) GetTotalUnreadThreads(userId string, teamID stri
|
||||
|
||||
}
|
||||
|
||||
func (s *RetryLayerThreadStore) GetTotalUnreadUrgentMentions(userId string, teamID string, opts model.GetUserThreadsOpts) (int64, error) {
|
||||
|
||||
tries := 0
|
||||
for {
|
||||
result, err := s.ThreadStore.GetTotalUnreadUrgentMentions(userId, teamID, opts)
|
||||
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 *RetryLayerThreadStore) MaintainMembership(userID string, postID string, opts store.ThreadMembershipOpts) (*model.ThreadMembership, error) {
|
||||
|
||||
tries := 0
|
||||
@@ -14261,6 +14355,7 @@ func New(childStore store.Store) *RetryLayer {
|
||||
newStore.OAuthStore = &RetryLayerOAuthStore{OAuthStore: childStore.OAuth(), Root: &newStore}
|
||||
newStore.PluginStore = &RetryLayerPluginStore{PluginStore: childStore.Plugin(), Root: &newStore}
|
||||
newStore.PostStore = &RetryLayerPostStore{PostStore: childStore.Post(), Root: &newStore}
|
||||
newStore.PostPriorityStore = &RetryLayerPostPriorityStore{PostPriorityStore: childStore.PostPriority(), Root: &newStore}
|
||||
newStore.PreferenceStore = &RetryLayerPreferenceStore{PreferenceStore: childStore.Preference(), Root: &newStore}
|
||||
newStore.ProductNoticesStore = &RetryLayerProductNoticesStore{ProductNoticesStore: childStore.ProductNotices(), Root: &newStore}
|
||||
newStore.ReactionStore = &RetryLayerReactionStore{ReactionStore: childStore.Reaction(), Root: &newStore}
|
||||
|
||||
@@ -54,6 +54,7 @@ func genStore() *mocks.Store {
|
||||
mock.On("UserTermsOfService").Return(&mocks.UserTermsOfServiceStore{})
|
||||
mock.On("Webhook").Return(&mocks.WebhookStore{})
|
||||
mock.On("NotifyAdmin").Return(&mocks.NotifyAdminStore{})
|
||||
mock.On("PostPriority").Return(&mocks.PostPriorityStore{})
|
||||
return mock
|
||||
}
|
||||
|
||||
|
||||
@@ -41,36 +41,38 @@ type SqlChannelStore struct {
|
||||
}
|
||||
|
||||
type channelMember struct {
|
||||
ChannelId string
|
||||
UserId string
|
||||
Roles string
|
||||
LastViewedAt int64
|
||||
MsgCount int64
|
||||
MentionCount int64
|
||||
NotifyProps model.StringMap
|
||||
LastUpdateAt int64
|
||||
SchemeUser sql.NullBool
|
||||
SchemeAdmin sql.NullBool
|
||||
SchemeGuest sql.NullBool
|
||||
MentionCountRoot int64
|
||||
MsgCountRoot int64
|
||||
ChannelId string
|
||||
UserId string
|
||||
Roles string
|
||||
LastViewedAt int64
|
||||
MsgCount int64
|
||||
MentionCount int64
|
||||
UrgentMentionCount int64
|
||||
NotifyProps model.StringMap
|
||||
LastUpdateAt int64
|
||||
SchemeUser sql.NullBool
|
||||
SchemeAdmin sql.NullBool
|
||||
SchemeGuest sql.NullBool
|
||||
MentionCountRoot int64
|
||||
MsgCountRoot int64
|
||||
}
|
||||
|
||||
func NewMapFromChannelMemberModel(cm *model.ChannelMember) map[string]any {
|
||||
return map[string]any{
|
||||
"ChannelId": cm.ChannelId,
|
||||
"UserId": cm.UserId,
|
||||
"Roles": cm.ExplicitRoles,
|
||||
"LastViewedAt": cm.LastViewedAt,
|
||||
"MsgCount": cm.MsgCount,
|
||||
"MentionCount": cm.MentionCount,
|
||||
"MentionCountRoot": cm.MentionCountRoot,
|
||||
"MsgCountRoot": cm.MsgCountRoot,
|
||||
"NotifyProps": cm.NotifyProps,
|
||||
"LastUpdateAt": cm.LastUpdateAt,
|
||||
"SchemeGuest": sql.NullBool{Valid: true, Bool: cm.SchemeGuest},
|
||||
"SchemeUser": sql.NullBool{Valid: true, Bool: cm.SchemeUser},
|
||||
"SchemeAdmin": sql.NullBool{Valid: true, Bool: cm.SchemeAdmin},
|
||||
"ChannelId": cm.ChannelId,
|
||||
"UserId": cm.UserId,
|
||||
"Roles": cm.ExplicitRoles,
|
||||
"LastViewedAt": cm.LastViewedAt,
|
||||
"MsgCount": cm.MsgCount,
|
||||
"MentionCount": cm.MentionCount,
|
||||
"MentionCountRoot": cm.MentionCountRoot,
|
||||
"UrgentMentionCount": cm.UrgentMentionCount,
|
||||
"MsgCountRoot": cm.MsgCountRoot,
|
||||
"NotifyProps": cm.NotifyProps,
|
||||
"LastUpdateAt": cm.LastUpdateAt,
|
||||
"SchemeGuest": sql.NullBool{Valid: true, Bool: cm.SchemeGuest},
|
||||
"SchemeUser": sql.NullBool{Valid: true, Bool: cm.SchemeUser},
|
||||
"SchemeAdmin": sql.NullBool{Valid: true, Bool: cm.SchemeAdmin},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,6 +84,7 @@ type channelMemberWithSchemeRoles struct {
|
||||
MsgCount int64
|
||||
MentionCount int64
|
||||
MentionCountRoot int64
|
||||
UrgentMentionCount int64
|
||||
NotifyProps model.StringMap
|
||||
LastUpdateAt int64
|
||||
SchemeGuest sql.NullBool
|
||||
@@ -106,7 +109,7 @@ type channelMemberWithTeamWithSchemeRoles struct {
|
||||
type channelMemberWithTeamWithSchemeRolesList []channelMemberWithTeamWithSchemeRoles
|
||||
|
||||
func channelMemberSliceColumns() []string {
|
||||
return []string{"ChannelId", "UserId", "Roles", "LastViewedAt", "MsgCount", "MsgCountRoot", "MentionCount", "MentionCountRoot", "NotifyProps", "LastUpdateAt", "SchemeUser", "SchemeAdmin", "SchemeGuest"}
|
||||
return []string{"ChannelId", "UserId", "Roles", "LastViewedAt", "MsgCount", "MsgCountRoot", "MentionCount", "MentionCountRoot", "UrgentMentionCount", "NotifyProps", "LastUpdateAt", "SchemeUser", "SchemeAdmin", "SchemeGuest"}
|
||||
}
|
||||
|
||||
func channelMemberToSlice(member *model.ChannelMember) []any {
|
||||
@@ -119,6 +122,7 @@ func channelMemberToSlice(member *model.ChannelMember) []any {
|
||||
resultSlice = append(resultSlice, member.MsgCountRoot)
|
||||
resultSlice = append(resultSlice, member.MentionCount)
|
||||
resultSlice = append(resultSlice, member.MentionCountRoot)
|
||||
resultSlice = append(resultSlice, member.UrgentMentionCount)
|
||||
resultSlice = append(resultSlice, model.MapToJSON(member.NotifyProps))
|
||||
resultSlice = append(resultSlice, member.LastUpdateAt)
|
||||
resultSlice = append(resultSlice, member.SchemeUser)
|
||||
@@ -244,20 +248,21 @@ func (db channelMemberWithSchemeRoles) ToModel() *model.ChannelMember {
|
||||
strings.Fields(db.Roles),
|
||||
)
|
||||
return &model.ChannelMember{
|
||||
ChannelId: db.ChannelId,
|
||||
UserId: db.UserId,
|
||||
Roles: strings.Join(rolesResult.roles, " "),
|
||||
LastViewedAt: db.LastViewedAt,
|
||||
MsgCount: db.MsgCount,
|
||||
MsgCountRoot: db.MsgCountRoot,
|
||||
MentionCount: db.MentionCount,
|
||||
MentionCountRoot: db.MentionCountRoot,
|
||||
NotifyProps: db.NotifyProps,
|
||||
LastUpdateAt: db.LastUpdateAt,
|
||||
SchemeAdmin: rolesResult.schemeAdmin,
|
||||
SchemeUser: rolesResult.schemeUser,
|
||||
SchemeGuest: rolesResult.schemeGuest,
|
||||
ExplicitRoles: strings.Join(rolesResult.explicitRoles, " "),
|
||||
ChannelId: db.ChannelId,
|
||||
UserId: db.UserId,
|
||||
Roles: strings.Join(rolesResult.roles, " "),
|
||||
LastViewedAt: db.LastViewedAt,
|
||||
MsgCount: db.MsgCount,
|
||||
MsgCountRoot: db.MsgCountRoot,
|
||||
MentionCount: db.MentionCount,
|
||||
MentionCountRoot: db.MentionCountRoot,
|
||||
UrgentMentionCount: db.UrgentMentionCount,
|
||||
NotifyProps: db.NotifyProps,
|
||||
LastUpdateAt: db.LastUpdateAt,
|
||||
SchemeAdmin: rolesResult.schemeAdmin,
|
||||
SchemeUser: rolesResult.schemeUser,
|
||||
SchemeGuest: rolesResult.schemeGuest,
|
||||
ExplicitRoles: strings.Join(rolesResult.explicitRoles, " "),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -307,20 +312,21 @@ func (db channelMemberWithTeamWithSchemeRoles) ToModel() *model.ChannelMemberWit
|
||||
)
|
||||
return &model.ChannelMemberWithTeamData{
|
||||
ChannelMember: model.ChannelMember{
|
||||
ChannelId: db.ChannelId,
|
||||
UserId: db.UserId,
|
||||
Roles: strings.Join(rolesResult.roles, " "),
|
||||
LastViewedAt: db.LastViewedAt,
|
||||
MsgCount: db.MsgCount,
|
||||
MsgCountRoot: db.MsgCountRoot,
|
||||
MentionCount: db.MentionCount,
|
||||
MentionCountRoot: db.MentionCountRoot,
|
||||
NotifyProps: db.NotifyProps,
|
||||
LastUpdateAt: db.LastUpdateAt,
|
||||
SchemeAdmin: rolesResult.schemeAdmin,
|
||||
SchemeUser: rolesResult.schemeUser,
|
||||
SchemeGuest: rolesResult.schemeGuest,
|
||||
ExplicitRoles: strings.Join(rolesResult.explicitRoles, " "),
|
||||
ChannelId: db.ChannelId,
|
||||
UserId: db.UserId,
|
||||
Roles: strings.Join(rolesResult.roles, " "),
|
||||
LastViewedAt: db.LastViewedAt,
|
||||
MsgCount: db.MsgCount,
|
||||
MsgCountRoot: db.MsgCountRoot,
|
||||
MentionCount: db.MentionCount,
|
||||
MentionCountRoot: db.MentionCountRoot,
|
||||
UrgentMentionCount: db.UrgentMentionCount,
|
||||
NotifyProps: db.NotifyProps,
|
||||
LastUpdateAt: db.LastUpdateAt,
|
||||
SchemeAdmin: rolesResult.schemeAdmin,
|
||||
SchemeUser: rolesResult.schemeUser,
|
||||
SchemeGuest: rolesResult.schemeGuest,
|
||||
ExplicitRoles: strings.Join(rolesResult.explicitRoles, " "),
|
||||
},
|
||||
TeamName: db.TeamName,
|
||||
TeamDisplayName: db.TeamDisplayName,
|
||||
@@ -471,7 +477,20 @@ func newSqlChannelStore(sqlStore *SqlStore, metrics einterfaces.MetricsInterface
|
||||
func (s *SqlChannelStore) initializeQueries() {
|
||||
s.channelMembersForTeamWithSchemeSelectQuery = s.getQueryBuilder().
|
||||
Select(
|
||||
"ChannelMembers.*",
|
||||
"ChannelMembers.ChannelId",
|
||||
"ChannelMembers.UserId",
|
||||
"ChannelMembers.Roles",
|
||||
"ChannelMembers.LastViewedAt",
|
||||
"ChannelMembers.MsgCount",
|
||||
"ChannelMembers.MentionCount",
|
||||
"ChannelMembers.MentionCountRoot",
|
||||
"COALESCE(ChannelMembers.UrgentMentionCount, 0) AS UrgentMentionCount",
|
||||
"ChannelMembers.MsgCountRoot",
|
||||
"ChannelMembers.NotifyProps",
|
||||
"ChannelMembers.LastUpdateAt",
|
||||
"ChannelMembers.SchemeUser",
|
||||
"ChannelMembers.SchemeAdmin",
|
||||
"ChannelMembers.SchemeGuest",
|
||||
"TeamScheme.DefaultChannelGuestRole TeamSchemeDefaultGuestRole",
|
||||
"TeamScheme.DefaultChannelUserRole TeamSchemeDefaultUserRole",
|
||||
"TeamScheme.DefaultChannelAdminRole TeamSchemeDefaultAdminRole",
|
||||
@@ -779,7 +798,7 @@ func (s SqlChannelStore) GetChannelUnread(channelId, userId string) (*model.Chan
|
||||
var unreadChannel model.ChannelUnread
|
||||
err := s.GetReplicaX().Get(&unreadChannel,
|
||||
`SELECT
|
||||
Channels.TeamId TeamId, Channels.Id ChannelId, (Channels.TotalMsgCount - ChannelMembers.MsgCount) MsgCount, (Channels.TotalMsgCountRoot - ChannelMembers.MsgCountRoot) MsgCountRoot, ChannelMembers.MentionCount MentionCount, ChannelMembers.MentionCountRoot MentionCountRoot, ChannelMembers.NotifyProps NotifyProps
|
||||
Channels.TeamId TeamId, Channels.Id ChannelId, (Channels.TotalMsgCount - ChannelMembers.MsgCount) MsgCount, (Channels.TotalMsgCountRoot - ChannelMembers.MsgCountRoot) MsgCountRoot, ChannelMembers.MentionCount MentionCount, ChannelMembers.MentionCountRoot MentionCountRoot, COALESCE(ChannelMembers.UrgentMentionCount, 0) UrgentMentionCount, ChannelMembers.NotifyProps NotifyProps
|
||||
FROM
|
||||
Channels, ChannelMembers
|
||||
WHERE
|
||||
@@ -1612,7 +1631,20 @@ func (s SqlChannelStore) GetDeleted(teamId string, offset int, limit int, userId
|
||||
|
||||
var channelMembersWithSchemeSelectQuery = `
|
||||
SELECT
|
||||
ChannelMembers.*,
|
||||
ChannelMembers.ChannelId,
|
||||
ChannelMembers.UserId,
|
||||
ChannelMembers.Roles,
|
||||
ChannelMembers.LastViewedAt,
|
||||
ChannelMembers.MsgCount,
|
||||
ChannelMembers.MentionCount,
|
||||
ChannelMembers.MentionCountRoot,
|
||||
COALESCE(ChannelMembers.UrgentMentionCount, 0) AS UrgentMentionCount,
|
||||
ChannelMembers.MsgCountRoot,
|
||||
ChannelMembers.NotifyProps,
|
||||
ChannelMembers.LastUpdateAt,
|
||||
ChannelMembers.SchemeUser,
|
||||
ChannelMembers.SchemeAdmin,
|
||||
ChannelMembers.SchemeGuest,
|
||||
COALESCE(Teams.DisplayName, '') TeamDisplayName,
|
||||
COALESCE(Teams.Name, '') TeamName,
|
||||
COALESCE(Teams.UpdateAt, 0) TeamUpdateAt,
|
||||
@@ -2048,7 +2080,20 @@ func (s SqlChannelStore) GetMemberForPost(postId string, userId string) (*model.
|
||||
var dbMember channelMemberWithSchemeRoles
|
||||
query := `
|
||||
SELECT
|
||||
ChannelMembers.*,
|
||||
ChannelMembers.ChannelId,
|
||||
ChannelMembers.UserId,
|
||||
ChannelMembers.Roles,
|
||||
ChannelMembers.LastViewedAt,
|
||||
ChannelMembers.MsgCount,
|
||||
ChannelMembers.MentionCount,
|
||||
ChannelMembers.MentionCountRoot,
|
||||
COALESCE(ChannelMembers.UrgentMentionCount, 0) AS UrgentMentionCount,
|
||||
ChannelMembers.MsgCountRoot,
|
||||
ChannelMembers.NotifyProps,
|
||||
ChannelMembers.LastUpdateAt,
|
||||
ChannelMembers.SchemeUser,
|
||||
ChannelMembers.SchemeAdmin,
|
||||
ChannelMembers.SchemeGuest,
|
||||
TeamScheme.DefaultChannelGuestRole TeamSchemeDefaultGuestRole,
|
||||
TeamScheme.DefaultChannelUserRole TeamSchemeDefaultUserRole,
|
||||
TeamScheme.DefaultChannelAdminRole TeamSchemeDefaultAdminRole,
|
||||
@@ -2438,6 +2483,7 @@ func (s SqlChannelStore) UpdateLastViewedAt(channelIds []string, userId string)
|
||||
Update("ChannelMembers cm").
|
||||
Set("MentionCount", 0).
|
||||
Set("MentionCountRoot", 0).
|
||||
Set("UrgentMentionCount", 0).
|
||||
Set("MsgCount", sq.Expr("greatest(cm.MsgCount, c.TotalMsgCount)")).
|
||||
Set("MsgCountRoot", sq.Expr("greatest(cm.MsgCountRoot, c.TotalMsgCountRoot)")).
|
||||
Set("LastViewedAt", sq.Expr("greatest(cm.LastViewedAt, c.LastPostAt)")).
|
||||
@@ -2497,6 +2543,7 @@ func (s SqlChannelStore) UpdateLastViewedAt(channelIds []string, userId string)
|
||||
updateQuery := s.getQueryBuilder().Update("ChannelMembers").
|
||||
Set("MentionCount", 0).
|
||||
Set("MentionCountRoot", 0).
|
||||
Set("UrgentMentionCount", 0).
|
||||
Set("MsgCount", msgCountQuery).
|
||||
Set("MsgCountRoot", msgCountQueryRoot).
|
||||
Set("LastViewedAt", lastViewedQuery).
|
||||
@@ -2518,6 +2565,31 @@ func (s SqlChannelStore) UpdateLastViewedAt(channelIds []string, userId string)
|
||||
return times, nil
|
||||
}
|
||||
|
||||
func (s SqlChannelStore) CountUrgentPostsAfter(channelId string, timestamp int64, userId string) (int, error) {
|
||||
query := s.getQueryBuilder().
|
||||
Select("count(*)").
|
||||
From("PostsPriority").
|
||||
Join("Posts ON Posts.Id = PostsPriority.PostId").
|
||||
Where(sq.And{
|
||||
sq.Eq{"PostsPriority.Priority": model.PostPriorityUrgent},
|
||||
sq.Eq{"Posts.ChannelId": channelId},
|
||||
sq.Gt{"Posts.CreateAt": timestamp},
|
||||
sq.Eq{"Posts.DeleteAt": 0},
|
||||
})
|
||||
|
||||
if userId != "" {
|
||||
query = query.Where(sq.Eq{"Posts.UserId": userId})
|
||||
}
|
||||
|
||||
var urgent int64
|
||||
err := s.GetReplicaX().GetBuilder(&urgent, query)
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "failed to count urgent Posts")
|
||||
}
|
||||
|
||||
return int(urgent), nil
|
||||
}
|
||||
|
||||
// CountPostsAfter returns the number of posts in the given channel created after but not including the given timestamp. If given a non-empty user ID, only counts posts made by that user.
|
||||
func (s SqlChannelStore) CountPostsAfter(channelId string, timestamp int64, userId string) (int, int, error) {
|
||||
joinLeavePostTypes := []string{
|
||||
@@ -2566,13 +2638,14 @@ func (s SqlChannelStore) CountPostsAfter(channelId string, timestamp int64, user
|
||||
if err != nil {
|
||||
return 0, 0, errors.Wrap(err, "failed to count root Posts")
|
||||
}
|
||||
|
||||
return int(unread), int(unreadRoot), nil
|
||||
}
|
||||
|
||||
// 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, setUnreadCountRoot bool) (*model.ChannelUnreadAt, error) {
|
||||
func (s SqlChannelStore) UpdateLastViewedAtPost(unreadPost *model.Post, userID string, mentionCount, mentionCountRoot, urgentMentionCount int, setUnreadCountRoot bool) (*model.ChannelUnreadAt, error) {
|
||||
unreadDate := unreadPost.CreateAt - 1
|
||||
|
||||
unread, unreadRoot, err := s.CountPostsAfter(unreadPost.ChannelId, unreadDate, "")
|
||||
@@ -2587,6 +2660,7 @@ func (s SqlChannelStore) UpdateLastViewedAtPost(unreadPost *model.Post, userID s
|
||||
params := map[string]any{
|
||||
"mentions": mentionCount,
|
||||
"mentionsroot": mentionCountRoot,
|
||||
"urgentmentions": urgentMentionCount,
|
||||
"unreadcount": unread,
|
||||
"unreadcountroot": unreadRoot,
|
||||
"lastviewedat": unreadDate,
|
||||
@@ -2603,6 +2677,7 @@ func (s SqlChannelStore) UpdateLastViewedAtPost(unreadPost *model.Post, userID s
|
||||
SET
|
||||
MentionCount = :mentions,
|
||||
MentionCountRoot = :mentionsroot,
|
||||
UrgentMentionCount = :urgentmentions,
|
||||
MsgCount = (SELECT TotalMsgCount FROM Channels WHERE ID = :channelid) - :unreadcount,
|
||||
MsgCountRoot = (SELECT TotalMsgCountRoot FROM Channels WHERE ID = :channelid) - :unreadcountroot,
|
||||
LastViewedAt = :lastviewedat,
|
||||
@@ -2625,6 +2700,7 @@ func (s SqlChannelStore) UpdateLastViewedAtPost(unreadPost *model.Post, userID s
|
||||
cm.MsgCountRoot MsgCountRoot,
|
||||
cm.MentionCount MentionCount,
|
||||
cm.MentionCountRoot MentionCountRoot,
|
||||
COALESCE(cm.UrgentMentionCount, 0) UrgentMentionCount,
|
||||
cm.LastViewedAt LastViewedAt,
|
||||
cm.NotifyProps NotifyProps
|
||||
FROM
|
||||
@@ -2643,7 +2719,7 @@ func (s SqlChannelStore) UpdateLastViewedAtPost(unreadPost *model.Post, userID s
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s SqlChannelStore) IncrementMentionCount(channelId string, userIDs []string, isRoot bool) error {
|
||||
func (s SqlChannelStore) IncrementMentionCount(channelId string, userIDs []string, isRoot bool, isUrgent bool) error {
|
||||
now := model.GetMillis()
|
||||
|
||||
rootInc := 0
|
||||
@@ -2651,10 +2727,16 @@ func (s SqlChannelStore) IncrementMentionCount(channelId string, userIDs []strin
|
||||
rootInc = 1
|
||||
}
|
||||
|
||||
urgentInc := 0
|
||||
if isUrgent {
|
||||
urgentInc = 1
|
||||
}
|
||||
|
||||
sql, args, err := s.getQueryBuilder().
|
||||
Update("ChannelMembers").
|
||||
Set("MentionCount", sq.Expr("MentionCount + 1")).
|
||||
Set("MentionCountRoot", sq.Expr("MentionCountRoot + ?", rootInc)).
|
||||
Set("UrgentMentionCount", sq.Expr("UrgentMentionCount + ?", urgentInc)).
|
||||
Set("LastUpdateAt", now).
|
||||
Where(sq.Eq{
|
||||
"UserId": userIDs,
|
||||
@@ -2832,7 +2914,21 @@ func (s SqlChannelStore) GetMembersForUser(teamID string, userID string) (model.
|
||||
|
||||
func (s SqlChannelStore) GetMembersForUserWithCursor(userID, teamID string, opts *store.ChannelMemberGraphQLSearchOpts) (model.ChannelMembers, error) {
|
||||
query := s.getQueryBuilder().
|
||||
Select("ChannelMembers.*",
|
||||
Select(
|
||||
"ChannelMembers.ChannelId",
|
||||
"ChannelMembers.UserId",
|
||||
"ChannelMembers.Roles",
|
||||
"ChannelMembers.LastViewedAt",
|
||||
"ChannelMembers.MsgCount",
|
||||
"ChannelMembers.MentionCount",
|
||||
"ChannelMembers.MentionCountRoot",
|
||||
"COALESCE(ChannelMembers.UrgentMentionCount, 0) AS UrgentMentionCount",
|
||||
"ChannelMembers.MsgCountRoot",
|
||||
"ChannelMembers.NotifyProps",
|
||||
"ChannelMembers.LastUpdateAt",
|
||||
"ChannelMembers.SchemeUser",
|
||||
"ChannelMembers.SchemeAdmin",
|
||||
"ChannelMembers.SchemeGuest",
|
||||
"TeamScheme.DefaultChannelGuestRole TeamSchemeDefaultGuestRole",
|
||||
"TeamScheme.DefaultChannelUserRole TeamSchemeDefaultUserRole",
|
||||
"TeamScheme.DefaultChannelAdminRole TeamSchemeDefaultAdminRole",
|
||||
@@ -3790,6 +3886,7 @@ func (s SqlChannelStore) MigrateChannelMembers(fromChannelId string, fromUserId
|
||||
LastViewedAt=:LastViewedAt,
|
||||
MsgCount=:MsgCount,
|
||||
MentionCount=:MentionCount,
|
||||
UrgentMentionCount=:UrgentMentionCount,
|
||||
NotifyProps=:NotifyProps,
|
||||
LastUpdateAt=:LastUpdateAt,
|
||||
SchemeUser=:SchemeUser,
|
||||
@@ -3932,6 +4029,7 @@ func (s SqlChannelStore) GetChannelMembersForExport(userId string, teamId string
|
||||
ChannelMembers.MsgCount,
|
||||
ChannelMembers.MentionCount,
|
||||
ChannelMembers.MentionCountRoot,
|
||||
COALESCE(ChannelMembers.UrgentMentionCount, 0) AS UrgentMentionCount,
|
||||
ChannelMembers.NotifyProps,
|
||||
ChannelMembers.LastUpdateAt,
|
||||
ChannelMembers.SchemeUser,
|
||||
@@ -3981,7 +4079,7 @@ func (s SqlChannelStore) GetAllDirectChannelsForExportAfter(limit int, afterId s
|
||||
channelIds = append(channelIds, channel.Id)
|
||||
}
|
||||
query = s.getQueryBuilder().
|
||||
Select("u.Username as Username, ChannelId, UserId, cm.Roles as Roles, LastViewedAt, MsgCount, MentionCount, MentionCountRoot, cm.NotifyProps as NotifyProps, LastUpdateAt, SchemeUser, SchemeAdmin, (SchemeGuest IS NOT NULL AND SchemeGuest) as SchemeGuest").
|
||||
Select("u.Username as Username, ChannelId, UserId, cm.Roles as Roles, LastViewedAt, MsgCount, MentionCount, MentionCountRoot, COALESCE(UrgentMentionCount, 0) UrgentMentionCount, cm.NotifyProps as NotifyProps, LastUpdateAt, SchemeUser, SchemeAdmin, (SchemeGuest IS NOT NULL AND SchemeGuest) as SchemeGuest").
|
||||
From("ChannelMembers cm").
|
||||
Join("Users u ON ( u.Id = cm.UserId )").
|
||||
Where(sq.And{
|
||||
|
||||
63
store/sqlstore/post_priority_store.go
Обычный файл
63
store/sqlstore/post_priority_store.go
Обычный файл
@@ -0,0 +1,63 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package sqlstore
|
||||
|
||||
import (
|
||||
"github.com/mattermost/mattermost-server/v6/model"
|
||||
"github.com/mattermost/mattermost-server/v6/store"
|
||||
sq "github.com/mattermost/squirrel"
|
||||
)
|
||||
|
||||
type SqlPostPriorityStore struct {
|
||||
*SqlStore
|
||||
}
|
||||
|
||||
func newSqlPostPriorityStore(sqlStore *SqlStore) store.PostPriorityStore {
|
||||
return &SqlPostPriorityStore{
|
||||
SqlStore: sqlStore,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SqlPostPriorityStore) GetForPost(postId string) (*model.PostPriority, error) {
|
||||
query := s.getQueryBuilder().
|
||||
Select("Priority", "RequestedAck", "PersistentNotifications").
|
||||
From("PostsPriority").
|
||||
Where(sq.Eq{"PostId": postId})
|
||||
|
||||
var postPriority model.PostPriority
|
||||
err := s.GetReplicaX().GetBuilder(&postPriority, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &postPriority, nil
|
||||
}
|
||||
|
||||
func (s *SqlPostPriorityStore) GetForPosts(postIds []string) ([]*model.PostPriority, error) {
|
||||
var priority []*model.PostPriority
|
||||
|
||||
perPage := 200
|
||||
for i := 0; i < len(postIds); i += perPage {
|
||||
j := i + perPage
|
||||
if len(postIds) < j {
|
||||
j = len(postIds)
|
||||
}
|
||||
|
||||
query := s.getQueryBuilder().
|
||||
Select("PostId", "Priority", "RequestedAck", "PersistentNotifications").
|
||||
From("PostsPriority").
|
||||
Where(sq.Eq{"PostId": postIds[i:j]})
|
||||
|
||||
var priorityBatch []*model.PostPriority
|
||||
err := s.GetReplicaX().SelectBuilder(&priority, query)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
priority = append(priority, priorityBatch...)
|
||||
}
|
||||
|
||||
return priority, nil
|
||||
}
|
||||
14
store/sqlstore/post_priority_store_test.go
Обычный файл
14
store/sqlstore/post_priority_store_test.go
Обычный файл
@@ -0,0 +1,14 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package sqlstore
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/mattermost/mattermost-server/v6/store/storetest"
|
||||
)
|
||||
|
||||
func TestPostPriorityStore(t *testing.T) {
|
||||
StoreTestWithSqlStore(t, storetest.TestPostPriorityStore)
|
||||
}
|
||||
@@ -219,6 +219,10 @@ func (s *SqlPostStore) SaveMultiple(posts []*model.Post) ([]*model.Post, int, er
|
||||
return nil, -1, errors.Wrap(err, "update thread from posts failed")
|
||||
}
|
||||
|
||||
if err = s.savePostsPriority(transaction, posts); err != nil {
|
||||
return nil, -1, errors.Wrap(err, "failed to save PostPriority")
|
||||
}
|
||||
|
||||
if err = transaction.Commit(); err != nil {
|
||||
// don't need to rollback here since the transaction is already closed
|
||||
return posts, -1, errors.Wrap(err, "commit_transaction")
|
||||
@@ -2920,6 +2924,24 @@ func (s *SqlPostStore) updateThreadAfterReplyDeletion(transaction *sqlxTxWrapper
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SqlPostStore) savePostsPriority(transaction *sqlxTxWrapper, posts []*model.Post) error {
|
||||
for _, post := range posts {
|
||||
if post.GetPriority() != nil {
|
||||
postPriority := &model.PostPriority{
|
||||
PostId: post.Id,
|
||||
ChannelId: post.ChannelId,
|
||||
Priority: post.Metadata.Priority.Priority,
|
||||
RequestedAck: post.Metadata.Priority.RequestedAck,
|
||||
PersistentNotifications: post.Metadata.Priority.PersistentNotifications,
|
||||
}
|
||||
if _, err := transaction.NamedExec(`INSERT INTO PostsPriority (PostId, ChannelId, Priority, RequestedAck, PersistentNotifications) VALUES (:PostId, :ChannelId, :Priority, :RequestedAck, :PersistentNotifications)`, postPriority); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SqlPostStore) updateThreadsFromPosts(transaction *sqlxTxWrapper, posts []*model.Post) error {
|
||||
postsByRoot := map[string][]*model.Post{}
|
||||
var rootIds []string
|
||||
|
||||
@@ -109,6 +109,7 @@ type SqlStoreStores struct {
|
||||
linkMetadata store.LinkMetadataStore
|
||||
sharedchannel store.SharedChannelStore
|
||||
notifyAdmin store.NotifyAdminStore
|
||||
postPriority store.PostPriorityStore
|
||||
}
|
||||
|
||||
type SqlStore struct {
|
||||
@@ -214,6 +215,7 @@ func New(settings model.SqlSettings, metrics einterfaces.MetricsInterface) *SqlS
|
||||
store.stores.group = newSqlGroupStore(store)
|
||||
store.stores.productNotices = newSqlProductNoticesStore(store)
|
||||
store.stores.notifyAdmin = newSqlNotifyAdminStore(store)
|
||||
store.stores.postPriority = newSqlPostPriorityStore(store)
|
||||
|
||||
store.stores.preference.(*SqlPreferenceStore).deleteUnusedFeatures()
|
||||
|
||||
@@ -955,6 +957,10 @@ func (ss *SqlStore) SharedChannel() store.SharedChannelStore {
|
||||
return ss.stores.sharedchannel
|
||||
}
|
||||
|
||||
func (ss *SqlStore) PostPriority() store.PostPriorityStore {
|
||||
return ss.stores.postPriority
|
||||
}
|
||||
|
||||
func (ss *SqlStore) DropAllTables() {
|
||||
if ss.DriverName() == model.DatabaseDriverPostgres {
|
||||
ss.masterX.Exec(`DO
|
||||
|
||||
@@ -7,11 +7,11 @@ import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
sq "github.com/mattermost/squirrel"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/sync/errgroup"
|
||||
|
||||
"github.com/mattermost/mattermost-server/v6/model"
|
||||
"github.com/mattermost/mattermost-server/v6/store"
|
||||
@@ -30,6 +30,7 @@ type JoinedThread struct {
|
||||
Participants model.StringArray
|
||||
ThreadDeleteAt int64
|
||||
TeamId string
|
||||
IsUrgent bool
|
||||
model.Post
|
||||
}
|
||||
|
||||
@@ -51,6 +52,7 @@ func (thread *JoinedThread) toThreadResponse(users map[string]*model.User) *mode
|
||||
Participants: threadParticipants,
|
||||
Post: thread.Post.ToNilIfInvalid(),
|
||||
DeleteAt: thread.ThreadDeleteAt,
|
||||
IsUrgent: thread.IsUrgent,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -213,6 +215,46 @@ func (s *SqlThreadStore) GetTotalUnreadMentions(userId, teamId string, opts mode
|
||||
return totalUnreadMentions, nil
|
||||
}
|
||||
|
||||
// GetTotalUnreadUrgentMentions counts the number of unread mentions for the given user, optionally
|
||||
// constrained to the given team + DMs/GMs.
|
||||
func (s *SqlThreadStore) GetTotalUnreadUrgentMentions(userId, teamId string, opts model.GetUserThreadsOpts) (int64, error) {
|
||||
var totalUnreadUrgentMentions int64
|
||||
|
||||
query := s.getQueryBuilder().
|
||||
Select("COALESCE(SUM(ThreadMemberships.UnreadMentions),0)").
|
||||
From("ThreadMemberships").
|
||||
Join("PostsPriority ON PostsPriority.PostId = ThreadMemberships.PostId").
|
||||
Where(sq.Eq{
|
||||
"ThreadMemberships.UserId": userId,
|
||||
"ThreadMemberships.Following": true,
|
||||
"PostsPriority.Priority": model.PostPriorityUrgent,
|
||||
})
|
||||
|
||||
if teamId != "" || !opts.Deleted {
|
||||
query = query.Join("Threads ON Threads.PostId = ThreadMemberships.PostId")
|
||||
}
|
||||
|
||||
if teamId != "" {
|
||||
query = query.
|
||||
Where(sq.Or{
|
||||
sq.Eq{"Threads.ThreadTeamId": teamId},
|
||||
sq.Eq{"Threads.ThreadTeamId": ""},
|
||||
})
|
||||
}
|
||||
|
||||
if !opts.Deleted {
|
||||
query = query.
|
||||
Where(sq.Eq{"COALESCE(Threads.ThreadDeleteAt, 0)": 0})
|
||||
}
|
||||
|
||||
err := s.GetReplicaX().GetBuilder(&totalUnreadUrgentMentions, query)
|
||||
if err != nil {
|
||||
return 0, errors.Wrapf(err, "failed to count unread urgent mentions for user id=%s", userId)
|
||||
}
|
||||
|
||||
return totalUnreadUrgentMentions, nil
|
||||
}
|
||||
|
||||
func (s *SqlThreadStore) GetThreadsForUser(userId, teamId string, opts model.GetUserThreadsOpts) ([]*model.ThreadResponse, error) {
|
||||
pageSize := uint64(30)
|
||||
if opts.PageSize != 0 {
|
||||
@@ -243,6 +285,17 @@ func (s *SqlThreadStore) GetThreadsForUser(userId, teamId string, opts model.Get
|
||||
Where(sq.Eq{"ThreadMemberships.UserId": userId}).
|
||||
Where(sq.Eq{"ThreadMemberships.Following": true})
|
||||
|
||||
if opts.IncludeIsUrgent {
|
||||
urgencyCase := sq.
|
||||
Case().
|
||||
When(sq.Eq{"PostsPriority.Priority": model.PostPriorityUrgent}, "true").
|
||||
Else("false")
|
||||
|
||||
query = query.
|
||||
Column(sq.Alias(urgencyCase, "IsUrgent")).
|
||||
LeftJoin("PostsPriority ON PostsPriority.PostId = Threads.PostId")
|
||||
}
|
||||
|
||||
// If a team is specified, constrain to channels in that team or DMs/GMs without
|
||||
// a team at all.
|
||||
if teamId != "" {
|
||||
@@ -322,7 +375,7 @@ func (s *SqlThreadStore) GetThreadsForUser(userId, teamId string, opts model.Get
|
||||
|
||||
// GetTeamsUnreadForUser returns the total unread threads and unread mentions
|
||||
// for a user from all teams.
|
||||
func (s *SqlThreadStore) GetTeamsUnreadForUser(userID string, teamIDs []string) (map[string]*model.TeamUnread, error) {
|
||||
func (s *SqlThreadStore) GetTeamsUnreadForUser(userID string, teamIDs []string, includeUrgentMentionCount bool) (map[string]*model.TeamUnread, error) {
|
||||
fetchConditions := sq.And{
|
||||
sq.Eq{"ThreadMemberships.UserId": userID},
|
||||
sq.Eq{"ThreadMemberships.Following": true},
|
||||
@@ -330,8 +383,7 @@ func (s *SqlThreadStore) GetTeamsUnreadForUser(userID string, teamIDs []string)
|
||||
sq.Eq{"COALESCE(Threads.ThreadDeleteAt, 0)": 0},
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
var err1, err2 error
|
||||
var eg errgroup.Group
|
||||
|
||||
unreadThreads := []struct {
|
||||
Count int64
|
||||
@@ -341,13 +393,15 @@ func (s *SqlThreadStore) GetTeamsUnreadForUser(userID string, teamIDs []string)
|
||||
Count int64
|
||||
TeamId string
|
||||
}{}
|
||||
unreadUrgentMentions := []struct {
|
||||
Count int64
|
||||
TeamId string
|
||||
}{}
|
||||
|
||||
// Running these concurrently hasn't shown any major downside
|
||||
// than running them serially. So using a bit of perf boost.
|
||||
// In any case, they will be replaced by computed columns later.
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
eg.Go(func() error {
|
||||
repliesQuery := s.getQueryBuilder().
|
||||
Select("COUNT(Threads.PostId) AS Count, ThreadTeamId AS TeamId").
|
||||
From("Threads").
|
||||
@@ -356,15 +410,10 @@ func (s *SqlThreadStore) GetTeamsUnreadForUser(userID string, teamIDs []string)
|
||||
Where("Threads.LastReplyAt > ThreadMemberships.LastViewed").
|
||||
GroupBy("Threads.ThreadTeamId")
|
||||
|
||||
err := s.GetReplicaX().SelectBuilder(&unreadThreads, repliesQuery)
|
||||
if err != nil {
|
||||
err1 = errors.Wrap(err, "failed to get total unread threads")
|
||||
}
|
||||
}()
|
||||
return errors.Wrap(s.GetReplicaX().SelectBuilder(&unreadThreads, repliesQuery), "failed to get total unread threads")
|
||||
})
|
||||
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
eg.Go(func() error {
|
||||
mentionsQuery := s.getQueryBuilder().
|
||||
Select("COALESCE(SUM(ThreadMemberships.UnreadMentions),0) AS Count, ThreadTeamId AS TeamId").
|
||||
From("ThreadMemberships").
|
||||
@@ -372,20 +421,27 @@ func (s *SqlThreadStore) GetTeamsUnreadForUser(userID string, teamIDs []string)
|
||||
Where(fetchConditions).
|
||||
GroupBy("Threads.ThreadTeamId")
|
||||
|
||||
err := s.GetReplicaX().SelectBuilder(&unreadMentions, mentionsQuery)
|
||||
if err != nil {
|
||||
err2 = errors.Wrap(err, "failed to get total unread mentions")
|
||||
}
|
||||
}()
|
||||
return errors.Wrap(s.GetReplicaX().SelectBuilder(&unreadMentions, mentionsQuery), "failed to get total unread mentions")
|
||||
})
|
||||
|
||||
if includeUrgentMentionCount {
|
||||
eg.Go(func() error {
|
||||
urgentMentionsQuery := s.getQueryBuilder().
|
||||
Select("COALESCE(SUM(ThreadMemberships.UnreadMentions),0) AS Count, ThreadTeamId AS TeamId").
|
||||
From("ThreadMemberships").
|
||||
LeftJoin("Threads ON Threads.PostId = ThreadMemberships.PostId").
|
||||
Join("PostsPriority ON PostsPriority.PostId = ThreadMemberships.PostId").
|
||||
Where(sq.Eq{"PostsPriority.Priority": model.PostPriorityUrgent}).
|
||||
Where(fetchConditions).
|
||||
GroupBy("Threads.ThreadTeamId")
|
||||
|
||||
return errors.Wrap(s.GetReplicaX().SelectBuilder(&unreadUrgentMentions, urgentMentionsQuery), "failed to get total unread urgent mentions")
|
||||
})
|
||||
}
|
||||
|
||||
// Wait for them to be over
|
||||
wg.Wait()
|
||||
|
||||
if err1 != nil {
|
||||
return nil, err1
|
||||
}
|
||||
if err2 != nil {
|
||||
return nil, err2
|
||||
if err := eg.Wait(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res := make(map[string]*model.TeamUnread)
|
||||
@@ -405,6 +461,15 @@ func (s *SqlThreadStore) GetTeamsUnreadForUser(userID string, teamIDs []string)
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, item := range unreadUrgentMentions {
|
||||
if _, ok := res[item.TeamId]; ok {
|
||||
res[item.TeamId].ThreadUrgentMentionCount = item.Count
|
||||
} else {
|
||||
res[item.TeamId] = &model.TeamUnread{
|
||||
ThreadUrgentMentionCount: item.Count,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
@@ -436,7 +501,7 @@ func (s *SqlThreadStore) GetThreadFollowers(threadID string, fetchOnlyActive boo
|
||||
return users, nil
|
||||
}
|
||||
|
||||
func (s *SqlThreadStore) GetThreadForUser(threadMembership *model.ThreadMembership, extended bool) (*model.ThreadResponse, error) {
|
||||
func (s *SqlThreadStore) GetThreadForUser(threadMembership *model.ThreadMembership, extended, postPriorityEnabled bool) (*model.ThreadResponse, error) {
|
||||
if !threadMembership.Following {
|
||||
return nil, nil // in case the thread is not followed anymore - return nil error to be interpreted as 404
|
||||
}
|
||||
@@ -462,6 +527,17 @@ func (s *SqlThreadStore) GetThreadForUser(threadMembership *model.ThreadMembersh
|
||||
LeftJoin("Posts ON Posts.Id = Threads.PostId").
|
||||
Where(sq.Eq{"Threads.PostId": threadMembership.PostId})
|
||||
|
||||
if postPriorityEnabled {
|
||||
urgencyCase := sq.
|
||||
Case().
|
||||
When(sq.Eq{"PostsPriority.Priority": model.PostPriorityUrgent}, "true").
|
||||
Else("false")
|
||||
|
||||
query = query.
|
||||
Column(sq.Alias(urgencyCase, "IsUrgent")).
|
||||
LeftJoin("PostsPriority ON PostsPriority.PostId = Threads.PostId")
|
||||
}
|
||||
|
||||
err := s.GetReplicaX().GetBuilder(&thread, query)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
|
||||
@@ -84,6 +84,7 @@ type Store interface {
|
||||
SetContext(context context.Context)
|
||||
Context() context.Context
|
||||
NotifyAdmin() NotifyAdminStore
|
||||
PostPriority() PostPriorityStore
|
||||
}
|
||||
|
||||
type RetentionPolicyStore interface {
|
||||
@@ -240,9 +241,10 @@ type ChannelStore interface {
|
||||
PermanentDeleteMembersByUser(userID string) error
|
||||
PermanentDeleteMembersByChannel(channelID string) error
|
||||
UpdateLastViewedAt(channelIds []string, userID string) (map[string]int64, error)
|
||||
UpdateLastViewedAtPost(unreadPost *model.Post, userID string, mentionCount, mentionCountRoot int, setUnreadCountRoot bool) (*model.ChannelUnreadAt, error)
|
||||
UpdateLastViewedAtPost(unreadPost *model.Post, userID string, mentionCount, mentionCountRoot, urgentMentionCount int, setUnreadCountRoot bool) (*model.ChannelUnreadAt, error)
|
||||
CountPostsAfter(channelID string, timestamp int64, userID string) (int, int, error)
|
||||
IncrementMentionCount(channelID string, userIDs []string, isRoot bool) error
|
||||
CountUrgentPostsAfter(channelID string, timestamp int64, userID string) (int, error)
|
||||
IncrementMentionCount(channelID string, userIDs []string, isRoot, isUrgent bool) error
|
||||
AnalyticsTypeCount(teamID string, channelType model.ChannelType) (int64, error)
|
||||
GetMembersForUser(teamID string, userID string) (model.ChannelMembers, error)
|
||||
GetTeamMembersForChannel(channelID string) ([]string, error)
|
||||
@@ -322,9 +324,10 @@ type ThreadStore interface {
|
||||
GetTotalUnreadThreads(userId, teamID string, opts model.GetUserThreadsOpts) (int64, error)
|
||||
GetTotalThreads(userId, teamID string, opts model.GetUserThreadsOpts) (int64, error)
|
||||
GetTotalUnreadMentions(userId, teamID string, opts model.GetUserThreadsOpts) (int64, error)
|
||||
GetTotalUnreadUrgentMentions(userId, teamID string, opts model.GetUserThreadsOpts) (int64, error)
|
||||
GetThreadsForUser(userId, teamID string, opts model.GetUserThreadsOpts) ([]*model.ThreadResponse, error)
|
||||
GetThreadForUser(threadMembership *model.ThreadMembership, extended bool) (*model.ThreadResponse, error)
|
||||
GetTeamsUnreadForUser(userID string, teamIDs []string) (map[string]*model.TeamUnread, error)
|
||||
GetThreadForUser(threadMembership *model.ThreadMembership, extended, postPriorityIsEnabled bool) (*model.ThreadResponse, error)
|
||||
GetTeamsUnreadForUser(userID string, teamIDs []string, includeUrgentMentionCount bool) (map[string]*model.TeamUnread, error)
|
||||
|
||||
MarkAllAsRead(userID string, threadIds []string) error
|
||||
MarkAllAsReadByTeam(userID, teamID string) error
|
||||
@@ -970,6 +973,11 @@ type SharedChannelStore interface {
|
||||
UpdateAttachmentLastSyncAt(id string, syncTime int64) error
|
||||
}
|
||||
|
||||
type PostPriorityStore interface {
|
||||
GetForPost(postId string) (*model.PostPriority, error)
|
||||
GetForPosts(ids []string) ([]*model.PostPriority, error)
|
||||
}
|
||||
|
||||
// ChannelSearchOpts contains options for searching channels.
|
||||
//
|
||||
// NotAssociatedToGroup will exclude channels that have associated, active GroupChannels records.
|
||||
|
||||
@@ -104,6 +104,7 @@ func TestChannelStore(t *testing.T, ss store.Store, s SqlStore) {
|
||||
t.Run("GetMembersForUserWithCursor", func(t *testing.T) { testChannelStoreGetMembersForUserWithCursor(t, ss) })
|
||||
t.Run("GetMembersForUserWithPagination", func(t *testing.T) { testChannelStoreGetMembersForUserWithPagination(t, ss) })
|
||||
t.Run("CountPostsAfter", func(t *testing.T) { testCountPostsAfter(t, ss) })
|
||||
t.Run("CountUrgentPostsAfter", func(t *testing.T) { testCountUrgentPostsAfter(t, ss) })
|
||||
t.Run("UpdateLastViewedAt", func(t *testing.T) { testChannelStoreUpdateLastViewedAt(t, ss) })
|
||||
t.Run("IncrementMentionCount", func(t *testing.T) { testChannelStoreIncrementMentionCount(t, ss) })
|
||||
t.Run("UpdateChannelMember", func(t *testing.T) { testUpdateChannelMember(t, ss) })
|
||||
@@ -4833,6 +4834,66 @@ func testCountPostsAfter(t *testing.T, ss store.Store) {
|
||||
})
|
||||
}
|
||||
|
||||
func testCountUrgentPostsAfter(t *testing.T, ss store.Store) {
|
||||
t.Run("should count all posts with or without the given user ID", func(t *testing.T) {
|
||||
userId1 := model.NewId()
|
||||
userId2 := model.NewId()
|
||||
|
||||
channelId := model.NewId()
|
||||
|
||||
p1, err := ss.Post().Save(&model.Post{
|
||||
UserId: userId1,
|
||||
ChannelId: channelId,
|
||||
CreateAt: 1000,
|
||||
Metadata: &model.PostMetadata{
|
||||
Priority: &model.PostPriority{
|
||||
Priority: model.NewString(model.PostPriorityUrgent),
|
||||
RequestedAck: model.NewBool(false),
|
||||
PersistentNotifications: model.NewBool(false),
|
||||
},
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = ss.Post().Save(&model.Post{
|
||||
UserId: userId1,
|
||||
ChannelId: channelId,
|
||||
CreateAt: 1001,
|
||||
Metadata: &model.PostMetadata{
|
||||
Priority: &model.PostPriority{
|
||||
Priority: model.NewString("important"),
|
||||
RequestedAck: model.NewBool(false),
|
||||
PersistentNotifications: model.NewBool(false),
|
||||
},
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = ss.Post().Save(&model.Post{
|
||||
UserId: userId2,
|
||||
ChannelId: channelId,
|
||||
CreateAt: 1002,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
count, err := ss.Channel().CountUrgentPostsAfter(channelId, p1.CreateAt-1, "")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 1, count)
|
||||
|
||||
count, err = ss.Channel().CountUrgentPostsAfter(channelId, p1.CreateAt, "")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 0, count)
|
||||
|
||||
count, err = ss.Channel().CountUrgentPostsAfter(channelId, p1.CreateAt-1, userId1)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 1, count)
|
||||
|
||||
count, err = ss.Channel().CountUrgentPostsAfter(channelId, p1.CreateAt, userId1)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 0, count)
|
||||
})
|
||||
}
|
||||
|
||||
func testChannelStoreUpdateLastViewedAt(t *testing.T, ss store.Store) {
|
||||
o1 := model.Channel{}
|
||||
o1.TeamId = model.NewId()
|
||||
@@ -4912,16 +4973,16 @@ func testChannelStoreIncrementMentionCount(t *testing.T, ss store.Store) {
|
||||
_, err := ss.Channel().SaveMember(&m1)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = ss.Channel().IncrementMentionCount(m1.ChannelId, []string{m1.UserId}, false)
|
||||
err = ss.Channel().IncrementMentionCount(m1.ChannelId, []string{m1.UserId}, false, false)
|
||||
require.NoError(t, err, "failed to update")
|
||||
|
||||
err = ss.Channel().IncrementMentionCount(m1.ChannelId, []string{"missing id"}, false)
|
||||
err = ss.Channel().IncrementMentionCount(m1.ChannelId, []string{"missing id"}, false, false)
|
||||
require.NoError(t, err, "failed to update")
|
||||
|
||||
err = ss.Channel().IncrementMentionCount("missing id", []string{m1.UserId}, false)
|
||||
err = ss.Channel().IncrementMentionCount("missing id", []string{m1.UserId}, false, false)
|
||||
require.NoError(t, err, "failed to update")
|
||||
|
||||
err = ss.Channel().IncrementMentionCount("missing id", []string{"missing id"}, false)
|
||||
err = ss.Channel().IncrementMentionCount("missing id", []string{"missing id"}, false, false)
|
||||
require.NoError(t, err, "failed to update")
|
||||
}
|
||||
|
||||
|
||||
@@ -192,6 +192,27 @@ func (_m *ChannelStore) CountPostsAfter(channelID string, timestamp int64, userI
|
||||
return r0, r1, r2
|
||||
}
|
||||
|
||||
// CountUrgentPostsAfter provides a mock function with given fields: channelID, timestamp, userID
|
||||
func (_m *ChannelStore) CountUrgentPostsAfter(channelID string, timestamp int64, userID string) (int, error) {
|
||||
ret := _m.Called(channelID, timestamp, userID)
|
||||
|
||||
var r0 int
|
||||
if rf, ok := ret.Get(0).(func(string, int64, string) int); ok {
|
||||
r0 = rf(channelID, timestamp, userID)
|
||||
} else {
|
||||
r0 = ret.Get(0).(int)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(string, int64, string) error); ok {
|
||||
r1 = rf(channelID, timestamp, userID)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// CreateDirectChannel provides a mock function with given fields: userID, otherUserID, channelOptions
|
||||
func (_m *ChannelStore) CreateDirectChannel(userID *model.User, otherUserID *model.User, channelOptions ...model.ChannelOption) (*model.Channel, error) {
|
||||
_va := make([]interface{}, len(channelOptions))
|
||||
@@ -1646,13 +1667,13 @@ func (_m *ChannelStore) GroupSyncedChannelCount() (int64, error) {
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// IncrementMentionCount provides a mock function with given fields: channelID, userIDs, isRoot
|
||||
func (_m *ChannelStore) IncrementMentionCount(channelID string, userIDs []string, isRoot bool) error {
|
||||
ret := _m.Called(channelID, userIDs, isRoot)
|
||||
// IncrementMentionCount provides a mock function with given fields: channelID, userIDs, isRoot, isUrgent
|
||||
func (_m *ChannelStore) IncrementMentionCount(channelID string, userIDs []string, isRoot bool, isUrgent bool) error {
|
||||
ret := _m.Called(channelID, userIDs, isRoot, isUrgent)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(string, []string, bool) error); ok {
|
||||
r0 = rf(channelID, userIDs, isRoot)
|
||||
if rf, ok := ret.Get(0).(func(string, []string, bool, bool) error); ok {
|
||||
r0 = rf(channelID, userIDs, isRoot, isUrgent)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
@@ -2192,13 +2213,13 @@ func (_m *ChannelStore) UpdateLastViewedAt(channelIds []string, userID string) (
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// UpdateLastViewedAtPost provides a mock function with given fields: unreadPost, userID, mentionCount, mentionCountRoot, setUnreadCountRoot
|
||||
func (_m *ChannelStore) UpdateLastViewedAtPost(unreadPost *model.Post, userID string, mentionCount int, mentionCountRoot int, setUnreadCountRoot bool) (*model.ChannelUnreadAt, error) {
|
||||
ret := _m.Called(unreadPost, userID, mentionCount, mentionCountRoot, setUnreadCountRoot)
|
||||
// UpdateLastViewedAtPost provides a mock function with given fields: unreadPost, userID, mentionCount, mentionCountRoot, urgentMentionCount, setUnreadCountRoot
|
||||
func (_m *ChannelStore) UpdateLastViewedAtPost(unreadPost *model.Post, userID string, mentionCount int, mentionCountRoot int, urgentMentionCount int, setUnreadCountRoot bool) (*model.ChannelUnreadAt, error) {
|
||||
ret := _m.Called(unreadPost, userID, mentionCount, mentionCountRoot, urgentMentionCount, 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, setUnreadCountRoot)
|
||||
if rf, ok := ret.Get(0).(func(*model.Post, string, int, int, int, bool) *model.ChannelUnreadAt); ok {
|
||||
r0 = rf(unreadPost, userID, mentionCount, mentionCountRoot, urgentMentionCount, setUnreadCountRoot)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*model.ChannelUnreadAt)
|
||||
@@ -2206,8 +2227,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, setUnreadCountRoot)
|
||||
if rf, ok := ret.Get(1).(func(*model.Post, string, int, int, int, bool) error); ok {
|
||||
r1 = rf(unreadPost, userID, mentionCount, mentionCountRoot, urgentMentionCount, setUnreadCountRoot)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
61
store/storetest/mocks/PostPriorityStore.go
Обычный файл
61
store/storetest/mocks/PostPriorityStore.go
Обычный файл
@@ -0,0 +1,61 @@
|
||||
// Code generated by mockery v2.10.4. DO NOT EDIT.
|
||||
|
||||
// Regenerate this file using `make store-mocks`.
|
||||
|
||||
package mocks
|
||||
|
||||
import (
|
||||
model "github.com/mattermost/mattermost-server/v6/model"
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
// PostPriorityStore is an autogenerated mock type for the PostPriorityStore type
|
||||
type PostPriorityStore struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// GetForPost provides a mock function with given fields: postId
|
||||
func (_m *PostPriorityStore) GetForPost(postId string) (*model.PostPriority, error) {
|
||||
ret := _m.Called(postId)
|
||||
|
||||
var r0 *model.PostPriority
|
||||
if rf, ok := ret.Get(0).(func(string) *model.PostPriority); ok {
|
||||
r0 = rf(postId)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*model.PostPriority)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(string) error); ok {
|
||||
r1 = rf(postId)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetForPosts provides a mock function with given fields: ids
|
||||
func (_m *PostPriorityStore) GetForPosts(ids []string) ([]*model.PostPriority, error) {
|
||||
ret := _m.Called(ids)
|
||||
|
||||
var r0 []*model.PostPriority
|
||||
if rf, ok := ret.Get(0).(func([]string) []*model.PostPriority); ok {
|
||||
r0 = rf(ids)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]*model.PostPriority)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func([]string) error); ok {
|
||||
r1 = rf(ids)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
@@ -475,6 +475,22 @@ func (_m *Store) Post() store.PostStore {
|
||||
return r0
|
||||
}
|
||||
|
||||
// PostPriority provides a mock function with given fields:
|
||||
func (_m *Store) PostPriority() store.PostPriorityStore {
|
||||
ret := _m.Called()
|
||||
|
||||
var r0 store.PostPriorityStore
|
||||
if rf, ok := ret.Get(0).(func() store.PostPriorityStore); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(store.PostPriorityStore)
|
||||
}
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// Preference provides a mock function with given fields:
|
||||
func (_m *Store) Preference() store.PreferenceStore {
|
||||
ret := _m.Called()
|
||||
|
||||
@@ -119,13 +119,13 @@ func (_m *ThreadStore) GetMembershipsForUser(userId string, teamID string) ([]*m
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetTeamsUnreadForUser provides a mock function with given fields: userID, teamIDs
|
||||
func (_m *ThreadStore) GetTeamsUnreadForUser(userID string, teamIDs []string) (map[string]*model.TeamUnread, error) {
|
||||
ret := _m.Called(userID, teamIDs)
|
||||
// GetTeamsUnreadForUser provides a mock function with given fields: userID, teamIDs, includeUrgentMentionCount
|
||||
func (_m *ThreadStore) GetTeamsUnreadForUser(userID string, teamIDs []string, includeUrgentMentionCount bool) (map[string]*model.TeamUnread, error) {
|
||||
ret := _m.Called(userID, teamIDs, includeUrgentMentionCount)
|
||||
|
||||
var r0 map[string]*model.TeamUnread
|
||||
if rf, ok := ret.Get(0).(func(string, []string) map[string]*model.TeamUnread); ok {
|
||||
r0 = rf(userID, teamIDs)
|
||||
if rf, ok := ret.Get(0).(func(string, []string, bool) map[string]*model.TeamUnread); ok {
|
||||
r0 = rf(userID, teamIDs, includeUrgentMentionCount)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(map[string]*model.TeamUnread)
|
||||
@@ -133,8 +133,8 @@ func (_m *ThreadStore) GetTeamsUnreadForUser(userID string, teamIDs []string) (m
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(string, []string) error); ok {
|
||||
r1 = rf(userID, teamIDs)
|
||||
if rf, ok := ret.Get(1).(func(string, []string, bool) error); ok {
|
||||
r1 = rf(userID, teamIDs, includeUrgentMentionCount)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
@@ -165,13 +165,13 @@ func (_m *ThreadStore) GetThreadFollowers(threadID string, fetchOnlyActive bool)
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetThreadForUser provides a mock function with given fields: threadMembership, extended
|
||||
func (_m *ThreadStore) GetThreadForUser(threadMembership *model.ThreadMembership, extended bool) (*model.ThreadResponse, error) {
|
||||
ret := _m.Called(threadMembership, extended)
|
||||
// GetThreadForUser provides a mock function with given fields: threadMembership, extended, postPriorityIsEnabled
|
||||
func (_m *ThreadStore) GetThreadForUser(threadMembership *model.ThreadMembership, extended bool, postPriorityIsEnabled bool) (*model.ThreadResponse, error) {
|
||||
ret := _m.Called(threadMembership, extended, postPriorityIsEnabled)
|
||||
|
||||
var r0 *model.ThreadResponse
|
||||
if rf, ok := ret.Get(0).(func(*model.ThreadMembership, bool) *model.ThreadResponse); ok {
|
||||
r0 = rf(threadMembership, extended)
|
||||
if rf, ok := ret.Get(0).(func(*model.ThreadMembership, bool, bool) *model.ThreadResponse); ok {
|
||||
r0 = rf(threadMembership, extended, postPriorityIsEnabled)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*model.ThreadResponse)
|
||||
@@ -179,8 +179,8 @@ func (_m *ThreadStore) GetThreadForUser(threadMembership *model.ThreadMembership
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(*model.ThreadMembership, bool) error); ok {
|
||||
r1 = rf(threadMembership, extended)
|
||||
if rf, ok := ret.Get(1).(func(*model.ThreadMembership, bool, bool) error); ok {
|
||||
r1 = rf(threadMembership, extended, postPriorityIsEnabled)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
@@ -341,6 +341,27 @@ func (_m *ThreadStore) GetTotalUnreadThreads(userId string, teamID string, opts
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetTotalUnreadUrgentMentions provides a mock function with given fields: userId, teamID, opts
|
||||
func (_m *ThreadStore) GetTotalUnreadUrgentMentions(userId string, teamID string, opts model.GetUserThreadsOpts) (int64, error) {
|
||||
ret := _m.Called(userId, teamID, opts)
|
||||
|
||||
var r0 int64
|
||||
if rf, ok := ret.Get(0).(func(string, string, model.GetUserThreadsOpts) int64); ok {
|
||||
r0 = rf(userId, teamID, opts)
|
||||
} else {
|
||||
r0 = ret.Get(0).(int64)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(string, string, model.GetUserThreadsOpts) error); ok {
|
||||
r1 = rf(userId, teamID, opts)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// MaintainMembership provides a mock function with given fields: userID, postID, opts
|
||||
func (_m *ThreadStore) MaintainMembership(userID string, postID string, opts store.ThreadMembershipOpts) (*model.ThreadMembership, error) {
|
||||
ret := _m.Called(userID, postID, opts)
|
||||
|
||||
72
store/storetest/post_priority_store.go
Обычный файл
72
store/storetest/post_priority_store.go
Обычный файл
@@ -0,0 +1,72 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package storetest
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/mattermost/mattermost-server/v6/model"
|
||||
"github.com/mattermost/mattermost-server/v6/store"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestPostPriorityStore(t *testing.T, ss store.Store, s SqlStore) {
|
||||
t.Run("GetForPost", func(t *testing.T) { testPostPriorityStoreGetForPost(t, ss) })
|
||||
}
|
||||
|
||||
func testPostPriorityStoreGetForPost(t *testing.T, ss store.Store) {
|
||||
|
||||
t.Run("Save post priority when in post's metadata", func(t *testing.T) {
|
||||
p1 := model.Post{}
|
||||
p1.ChannelId = model.NewId()
|
||||
p1.UserId = model.NewId()
|
||||
p1.Message = NewTestId()
|
||||
p1.Metadata = &model.PostMetadata{
|
||||
Priority: &model.PostPriority{
|
||||
Priority: model.NewString("important"),
|
||||
RequestedAck: model.NewBool(true),
|
||||
PersistentNotifications: model.NewBool(false),
|
||||
},
|
||||
}
|
||||
|
||||
p2 := model.Post{}
|
||||
p2.ChannelId = model.NewId()
|
||||
p2.UserId = model.NewId()
|
||||
p2.Message = NewTestId()
|
||||
p2.Metadata = &model.PostMetadata{
|
||||
Priority: &model.PostPriority{
|
||||
Priority: model.NewString(model.PostPriorityUrgent),
|
||||
RequestedAck: model.NewBool(false),
|
||||
PersistentNotifications: model.NewBool(true),
|
||||
},
|
||||
}
|
||||
|
||||
p3 := model.Post{}
|
||||
p3.ChannelId = model.NewId()
|
||||
p3.UserId = model.NewId()
|
||||
p3.Message = NewTestId()
|
||||
|
||||
_, errIdx, err := ss.Post().SaveMultiple([]*model.Post{&p1, &p2, &p3})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, -1, errIdx)
|
||||
|
||||
pp1, err := ss.PostPriority().GetForPost(p1.Id)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "important", *pp1.Priority)
|
||||
assert.Equal(t, true, *pp1.RequestedAck)
|
||||
assert.Equal(t, false, *pp1.PersistentNotifications)
|
||||
|
||||
pp2, err := ss.PostPriority().GetForPost(p2.Id)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, model.PostPriorityUrgent, *pp2.Priority)
|
||||
assert.Equal(t, false, *pp2.RequestedAck)
|
||||
assert.Equal(t, true, *pp2.PersistentNotifications)
|
||||
|
||||
_, err = ss.PostPriority().GetForPost(p3.Id)
|
||||
assert.True(t, errors.Is(err, sql.ErrNoRows))
|
||||
})
|
||||
}
|
||||
@@ -238,6 +238,31 @@ func testPostStoreSave(t *testing.T, ss store.Store) {
|
||||
assert.Greater(t, rchannel3.LastPostAt, rchannel2.LastPostAt)
|
||||
assert.Equal(t, int64(3), rchannel3.TotalMsgCount)
|
||||
})
|
||||
|
||||
t.Run("Save post with priority metadata set", func(t *testing.T) {
|
||||
o1 := model.Post{}
|
||||
o1.ChannelId = model.NewId()
|
||||
o1.UserId = model.NewId()
|
||||
o1.Message = NewTestId()
|
||||
|
||||
o1.Metadata = &model.PostMetadata{
|
||||
Priority: &model.PostPriority{
|
||||
Priority: model.NewString("important"),
|
||||
RequestedAck: model.NewBool(true),
|
||||
PersistentNotifications: model.NewBool(false),
|
||||
},
|
||||
}
|
||||
|
||||
p, err := ss.Post().Save(&o1)
|
||||
require.NoError(t, err, "couldn't save item")
|
||||
assert.Equal(t, int64(0), p.ReplyCount)
|
||||
|
||||
pp, err := ss.PostPriority().GetForPost(p.Id)
|
||||
require.NoError(t, err, "couldn't save item")
|
||||
assert.Equal(t, "important", *pp.Priority)
|
||||
assert.Equal(t, true, *pp.RequestedAck)
|
||||
assert.Equal(t, false, *pp.PersistentNotifications)
|
||||
})
|
||||
}
|
||||
|
||||
func testPostStoreSaveMultiple(t *testing.T, ss store.Store) {
|
||||
|
||||
@@ -56,6 +56,7 @@ type Store struct {
|
||||
ProductNoticesStore mocks.ProductNoticesStore
|
||||
context context.Context
|
||||
NotifyAdminStore mocks.NotifyAdminStore
|
||||
PostPriorityStore mocks.PostPriorityStore
|
||||
}
|
||||
|
||||
func (s *Store) SetContext(context context.Context) { s.context = context }
|
||||
@@ -100,6 +101,7 @@ func (s *Store) NotifyAdmin() store.NotifyAdminStore { return &s.NotifyAdmin
|
||||
func (s *Store) Group() store.GroupStore { return &s.GroupStore }
|
||||
func (s *Store) LinkMetadata() store.LinkMetadataStore { return &s.LinkMetadataStore }
|
||||
func (s *Store) SharedChannel() store.SharedChannelStore { return &s.SharedChannelStore }
|
||||
func (s *Store) PostPriority() store.PostPriorityStore { return &s.PostPriorityStore }
|
||||
func (s *Store) MarkSystemRanUnitTests() { /* do nothing */ }
|
||||
func (s *Store) Close() { /* do nothing */ }
|
||||
func (s *Store) LockToMaster() { /* do nothing */ }
|
||||
@@ -158,5 +160,6 @@ func (s *Store) AssertExpectations(t mock.TestingT) bool {
|
||||
&s.ProductNoticesStore,
|
||||
&s.SharedChannelStore,
|
||||
&s.NotifyAdminStore,
|
||||
&s.PostPriorityStore,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ func TestThreadStore(t *testing.T, ss store.Store, s SqlStore) {
|
||||
}
|
||||
|
||||
func testThreadStorePopulation(t *testing.T, ss store.Store) {
|
||||
makeSomePosts := func() []*model.Post {
|
||||
makeSomePosts := func(urgent bool) []*model.Post {
|
||||
|
||||
u1 := model.User{
|
||||
Email: MakeEmail(),
|
||||
@@ -61,6 +61,16 @@ func testThreadStorePopulation(t *testing.T, ss store.Store) {
|
||||
o.UserId = u.Id
|
||||
o.Message = NewTestId()
|
||||
|
||||
if urgent {
|
||||
o.Metadata = &model.PostMetadata{
|
||||
Priority: &model.PostPriority{
|
||||
Priority: model.NewString(model.PostPriorityUrgent),
|
||||
RequestedAck: model.NewBool(false),
|
||||
PersistentNotifications: model.NewBool(false),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
otmp, err3 := ss.Post().Save(&o)
|
||||
require.NoError(t, err3)
|
||||
o2 := model.Post{}
|
||||
@@ -100,7 +110,7 @@ func testThreadStorePopulation(t *testing.T, ss store.Store) {
|
||||
return newPosts
|
||||
}
|
||||
t.Run("Save replies creates a thread", func(t *testing.T) {
|
||||
newPosts := makeSomePosts()
|
||||
newPosts := makeSomePosts(false)
|
||||
thread, err := ss.Thread().Get(newPosts[0].Id)
|
||||
require.NoError(t, err, "couldn't get thread")
|
||||
require.NotNil(t, thread)
|
||||
@@ -133,7 +143,7 @@ func testThreadStorePopulation(t *testing.T, ss store.Store) {
|
||||
})
|
||||
|
||||
t.Run("Delete a reply updates count on a thread", func(t *testing.T) {
|
||||
newPosts := makeSomePosts()
|
||||
newPosts := makeSomePosts(false)
|
||||
thread, err := ss.Thread().Get(newPosts[0].Id)
|
||||
require.NoError(t, err, "couldn't get thread")
|
||||
require.NotNil(t, thread)
|
||||
@@ -307,7 +317,7 @@ func testThreadStorePopulation(t *testing.T, ss store.Store) {
|
||||
})
|
||||
|
||||
t.Run("Thread membership 'viewed' timestamp is updated properly", func(t *testing.T) {
|
||||
newPosts := makeSomePosts()
|
||||
newPosts := makeSomePosts(false)
|
||||
|
||||
opts := store.ThreadMembershipOpts{
|
||||
Following: true,
|
||||
@@ -341,7 +351,7 @@ func testThreadStorePopulation(t *testing.T, ss store.Store) {
|
||||
})
|
||||
|
||||
t.Run("Thread membership 'viewed' timestamp is updated properly for new membership", func(t *testing.T) {
|
||||
newPosts := makeSomePosts()
|
||||
newPosts := makeSomePosts(false)
|
||||
|
||||
opts := store.ThreadMembershipOpts{
|
||||
Following: true,
|
||||
@@ -356,7 +366,7 @@ func testThreadStorePopulation(t *testing.T, ss store.Store) {
|
||||
})
|
||||
|
||||
t.Run("Updating post does not make thread unread", func(t *testing.T) {
|
||||
newPosts := makeSomePosts()
|
||||
newPosts := makeSomePosts(false)
|
||||
opts := store.ThreadMembershipOpts{
|
||||
Following: true,
|
||||
IncrementMentions: false,
|
||||
@@ -366,14 +376,14 @@ func testThreadStorePopulation(t *testing.T, ss store.Store) {
|
||||
}
|
||||
m, err := ss.Thread().MaintainMembership(newPosts[0].UserId, newPosts[0].Id, opts)
|
||||
require.NoError(t, err)
|
||||
th, err := ss.Thread().GetThreadForUser(m, false)
|
||||
th, err := ss.Thread().GetThreadForUser(m, false, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, int64(2), th.UnreadReplies)
|
||||
|
||||
m.LastViewed = newPosts[2].UpdateAt + 1
|
||||
_, err = ss.Thread().UpdateMembership(m)
|
||||
require.NoError(t, err)
|
||||
th, err = ss.Thread().GetThreadForUser(m, false)
|
||||
th, err = ss.Thread().GetThreadForUser(m, false, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, int64(0), th.UnreadReplies)
|
||||
|
||||
@@ -382,13 +392,13 @@ func testThreadStorePopulation(t *testing.T, ss store.Store) {
|
||||
_, err = ss.Post().Update(editedPost, newPosts[2])
|
||||
require.NoError(t, err)
|
||||
|
||||
th, err = ss.Thread().GetThreadForUser(m, false)
|
||||
th, err = ss.Thread().GetThreadForUser(m, false, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, int64(0), th.UnreadReplies)
|
||||
})
|
||||
|
||||
t.Run("Empty participantID should not appear in thread response", func(t *testing.T) {
|
||||
newPosts := makeSomePosts()
|
||||
newPosts := makeSomePosts(false)
|
||||
opts := store.ThreadMembershipOpts{
|
||||
Following: true,
|
||||
IncrementMentions: false,
|
||||
@@ -399,7 +409,7 @@ func testThreadStorePopulation(t *testing.T, ss store.Store) {
|
||||
m, err := ss.Thread().MaintainMembership("", newPosts[0].Id, opts)
|
||||
require.NoError(t, err)
|
||||
m.UserId = newPosts[0].UserId
|
||||
th, err := ss.Thread().GetThreadForUser(m, true)
|
||||
th, err := ss.Thread().GetThreadForUser(m, true, false)
|
||||
require.NoError(t, err)
|
||||
for _, user := range th.Participants {
|
||||
require.NotNil(t, user)
|
||||
@@ -407,7 +417,7 @@ func testThreadStorePopulation(t *testing.T, ss store.Store) {
|
||||
})
|
||||
t.Run("Get unread reply counts for thread", func(t *testing.T) {
|
||||
t.Skip("MM-41797")
|
||||
newPosts := makeSomePosts()
|
||||
newPosts := makeSomePosts(false)
|
||||
opts := store.ThreadMembershipOpts{
|
||||
Following: true,
|
||||
IncrementMentions: false,
|
||||
@@ -435,6 +445,36 @@ func testThreadStorePopulation(t *testing.T, ss store.Store) {
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, int64(2), unreads)
|
||||
})
|
||||
|
||||
testCases := []bool{true, false}
|
||||
|
||||
for _, isUrgent := range testCases {
|
||||
t.Run("Return is urgent for user thread/s", func(t *testing.T) {
|
||||
newPosts := makeSomePosts(isUrgent)
|
||||
opts := store.ThreadMembershipOpts{
|
||||
Following: true,
|
||||
IncrementMentions: false,
|
||||
UpdateFollowing: true,
|
||||
UpdateViewedTimestamp: true,
|
||||
UpdateParticipants: false,
|
||||
}
|
||||
|
||||
userID := newPosts[0].UserId
|
||||
_, e := ss.Thread().MaintainMembership(userID, newPosts[0].Id, opts)
|
||||
require.NoError(t, e)
|
||||
|
||||
m, e := ss.Thread().GetMembershipForUser(userID, newPosts[0].Id)
|
||||
require.NoError(t, e)
|
||||
|
||||
th, e := ss.Thread().GetThreadForUser(m, false, true)
|
||||
require.NoError(t, e)
|
||||
require.Equal(t, isUrgent, th.IsUrgent)
|
||||
|
||||
threads, e := ss.Thread().GetThreadsForUser(userID, "", model.GetUserThreadsOpts{IncludeIsUrgent: true})
|
||||
require.NoError(t, e)
|
||||
require.Equal(t, isUrgent, threads[0].IsUrgent)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func threadStoreCreateReply(t *testing.T, ss store.Store, channelID, postID, userID string, createAt int64) *model.Post {
|
||||
@@ -660,7 +700,7 @@ func testGetTeamsUnreadForUser(t *testing.T, ss store.Store) {
|
||||
threadStoreCreateReply(t, ss, channel1.Id, post.Id, post.UserId, model.GetMillis())
|
||||
createThreadMembership(userID, post.Id)
|
||||
|
||||
teamsUnread, err := ss.Thread().GetTeamsUnreadForUser(userID, []string{team1.Id})
|
||||
teamsUnread, err := ss.Thread().GetTeamsUnreadForUser(userID, []string{team1.Id}, true)
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, teamsUnread, 1)
|
||||
assert.Equal(t, int64(1), teamsUnread[team1.Id].ThreadCount)
|
||||
@@ -674,7 +714,7 @@ func testGetTeamsUnreadForUser(t *testing.T, ss store.Store) {
|
||||
threadStoreCreateReply(t, ss, channel1.Id, post.Id, post.UserId, model.GetMillis())
|
||||
createThreadMembership(userID, post.Id)
|
||||
|
||||
teamsUnread, err = ss.Thread().GetTeamsUnreadForUser(userID, []string{team1.Id})
|
||||
teamsUnread, err = ss.Thread().GetTeamsUnreadForUser(userID, []string{team1.Id}, true)
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, teamsUnread, 1)
|
||||
assert.Equal(t, int64(2), teamsUnread[team1.Id].ThreadCount)
|
||||
@@ -693,16 +733,24 @@ func testGetTeamsUnreadForUser(t *testing.T, ss store.Store) {
|
||||
Type: model.ChannelTypeOpen,
|
||||
}, -1)
|
||||
require.NoError(t, err)
|
||||
|
||||
post2, err := ss.Post().Save(&model.Post{
|
||||
ChannelId: channel2.Id,
|
||||
UserId: userID,
|
||||
Message: model.NewRandomString(10),
|
||||
Metadata: &model.PostMetadata{
|
||||
Priority: &model.PostPriority{
|
||||
Priority: model.NewString(model.PostPriorityUrgent),
|
||||
RequestedAck: model.NewBool(false),
|
||||
PersistentNotifications: model.NewBool(false),
|
||||
},
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
threadStoreCreateReply(t, ss, channel2.Id, post2.Id, post2.UserId, model.GetMillis())
|
||||
createThreadMembership(userID, post2.Id)
|
||||
|
||||
teamsUnread, err = ss.Thread().GetTeamsUnreadForUser(userID, []string{team1.Id, team2.Id})
|
||||
teamsUnread, err = ss.Thread().GetTeamsUnreadForUser(userID, []string{team1.Id, team2.Id}, true)
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, teamsUnread, 2)
|
||||
assert.Equal(t, int64(2), teamsUnread[team1.Id].ThreadCount)
|
||||
@@ -715,11 +763,12 @@ func testGetTeamsUnreadForUser(t *testing.T, ss store.Store) {
|
||||
_, err = ss.Thread().MaintainMembership(userID, post2.Id, opts)
|
||||
require.NoError(t, err)
|
||||
|
||||
teamsUnread, err = ss.Thread().GetTeamsUnreadForUser(userID, []string{team2.Id})
|
||||
teamsUnread, err = ss.Thread().GetTeamsUnreadForUser(userID, []string{team2.Id}, true)
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, teamsUnread, 1)
|
||||
assert.Equal(t, int64(1), teamsUnread[team2.Id].ThreadCount)
|
||||
assert.Equal(t, int64(1), teamsUnread[team2.Id].ThreadMentionCount)
|
||||
assert.Equal(t, int64(1), teamsUnread[team2.Id].ThreadUrgentMentionCount)
|
||||
}
|
||||
|
||||
type byPostId []*model.Post
|
||||
@@ -831,6 +880,13 @@ func testVarious(t *testing.T, ss store.Store) {
|
||||
ChannelId: team1channel1.Id,
|
||||
UserId: user1ID,
|
||||
Message: model.NewRandomString(10),
|
||||
Metadata: &model.PostMetadata{
|
||||
Priority: &model.PostPriority{
|
||||
Priority: model.NewString(model.PostPriorityUrgent),
|
||||
RequestedAck: model.NewBool(false),
|
||||
PersistentNotifications: model.NewBool(false),
|
||||
},
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -1032,6 +1088,33 @@ func testVarious(t *testing.T, ss store.Store) {
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("GetTotalUnreadUrgentMentions", func(t *testing.T) {
|
||||
testCases := []struct {
|
||||
Description string
|
||||
UserID string
|
||||
TeamID string
|
||||
Options model.GetUserThreadsOpts
|
||||
ExpectedThreads []*model.Post
|
||||
}{
|
||||
{"all teams, user1", user1ID, "", model.GetUserThreadsOpts{}, []*model.Post{
|
||||
team1channel1post3,
|
||||
}},
|
||||
{"team1, user1", user1ID, team1.Id, model.GetUserThreadsOpts{}, []*model.Post{
|
||||
team1channel1post3,
|
||||
}},
|
||||
{"team2, user1", user1ID, team2.Id, model.GetUserThreadsOpts{}, []*model.Post{}},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.Description, func(t *testing.T) {
|
||||
totalUnreadUrgentMentions, err := ss.Thread().GetTotalUnreadUrgentMentions(testCase.UserID, testCase.TeamID, testCase.Options)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.EqualValues(t, int64(len(testCase.ExpectedThreads)), totalUnreadUrgentMentions)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
assertThreadPosts := func(t *testing.T, threads []*model.ThreadResponse, expectedPosts []*model.Post) {
|
||||
t.Helper()
|
||||
|
||||
@@ -1166,7 +1249,7 @@ func testMarkAllAsReadByChannels(t *testing.T, ss store.Store) {
|
||||
assertThreadReplyCount := func(t *testing.T, userID string, count int64) {
|
||||
t.Helper()
|
||||
|
||||
teamsUnread, err := ss.Thread().GetTeamsUnreadForUser(userID, []string{team1.Id})
|
||||
teamsUnread, err := ss.Thread().GetTeamsUnreadForUser(userID, []string{team1.Id}, false)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, teamsUnread, 1, "unexpected unread teams count")
|
||||
assert.Equal(t, count, teamsUnread[team1.Id].ThreadCount, "unexpected thread count")
|
||||
@@ -1623,7 +1706,7 @@ func testMarkAllAsReadByTeam(t *testing.T, ss store.Store) {
|
||||
assertThreadReplyCount := func(t *testing.T, userID, teamID string, count int64, message string) {
|
||||
t.Helper()
|
||||
|
||||
teamsUnread, err := ss.Thread().GetTeamsUnreadForUser(userID, []string{teamID})
|
||||
teamsUnread, err := ss.Thread().GetTeamsUnreadForUser(userID, []string{teamID}, true)
|
||||
require.NoError(t, err)
|
||||
require.Lenf(t, teamsUnread, 1, "unexpected unread teams count: %s", message)
|
||||
assert.Equalf(t, count, teamsUnread[teamID].ThreadCount, "unexpected thread count: %s", message)
|
||||
|
||||
@@ -2468,7 +2468,7 @@ func testUserUnreadCount(t *testing.T, ss store.Store) {
|
||||
// Post one message with mention to open channel
|
||||
_, nErr = ss.Post().Save(&p1)
|
||||
require.NoError(t, nErr)
|
||||
nErr = ss.Channel().IncrementMentionCount(c1.Id, []string{u2.Id, u3.Id}, false)
|
||||
nErr = ss.Channel().IncrementMentionCount(c1.Id, []string{u2.Id, u3.Id}, false, false)
|
||||
require.NoError(t, nErr)
|
||||
|
||||
// Post 2 messages without mention to direct channel
|
||||
@@ -2479,7 +2479,7 @@ func testUserUnreadCount(t *testing.T, ss store.Store) {
|
||||
|
||||
_, nErr = ss.Post().Save(&p2)
|
||||
require.NoError(t, nErr)
|
||||
nErr = ss.Channel().IncrementMentionCount(c2.Id, []string{u2.Id}, false)
|
||||
nErr = ss.Channel().IncrementMentionCount(c2.Id, []string{u2.Id}, false, false)
|
||||
require.NoError(t, nErr)
|
||||
|
||||
p3 := model.Post{}
|
||||
@@ -2489,7 +2489,7 @@ func testUserUnreadCount(t *testing.T, ss store.Store) {
|
||||
_, nErr = ss.Post().Save(&p3)
|
||||
require.NoError(t, nErr)
|
||||
|
||||
nErr = ss.Channel().IncrementMentionCount(c2.Id, []string{u2.Id}, false)
|
||||
nErr = ss.Channel().IncrementMentionCount(c2.Id, []string{u2.Id}, false, false)
|
||||
require.NoError(t, nErr)
|
||||
|
||||
badge, unreadCountErr := ss.User().GetUnreadCount(u2.Id, false)
|
||||
@@ -2501,7 +2501,7 @@ func testUserUnreadCount(t *testing.T, ss store.Store) {
|
||||
require.Equal(t, int64(1), badge, "should have 1 unread message")
|
||||
|
||||
// Increment root mentions by 1
|
||||
nErr = ss.Channel().IncrementMentionCount(c1.Id, []string{u3.Id}, true)
|
||||
nErr = ss.Channel().IncrementMentionCount(c1.Id, []string{u3.Id}, true, false)
|
||||
require.NoError(t, nErr)
|
||||
|
||||
// CRT is enabled, only root mentions are counted
|
||||
|
||||
@@ -36,6 +36,7 @@ type TimerLayer struct {
|
||||
OAuthStore store.OAuthStore
|
||||
PluginStore store.PluginStore
|
||||
PostStore store.PostStore
|
||||
PostPriorityStore store.PostPriorityStore
|
||||
PreferenceStore store.PreferenceStore
|
||||
ProductNoticesStore store.ProductNoticesStore
|
||||
ReactionStore store.ReactionStore
|
||||
@@ -130,6 +131,10 @@ func (s *TimerLayer) Post() store.PostStore {
|
||||
return s.PostStore
|
||||
}
|
||||
|
||||
func (s *TimerLayer) PostPriority() store.PostPriorityStore {
|
||||
return s.PostPriorityStore
|
||||
}
|
||||
|
||||
func (s *TimerLayer) Preference() store.PreferenceStore {
|
||||
return s.PreferenceStore
|
||||
}
|
||||
@@ -300,6 +305,11 @@ type TimerLayerPostStore struct {
|
||||
Root *TimerLayer
|
||||
}
|
||||
|
||||
type TimerLayerPostPriorityStore struct {
|
||||
store.PostPriorityStore
|
||||
Root *TimerLayer
|
||||
}
|
||||
|
||||
type TimerLayerPreferenceStore struct {
|
||||
store.PreferenceStore
|
||||
Root *TimerLayer
|
||||
@@ -671,6 +681,22 @@ func (s *TimerLayerChannelStore) CountPostsAfter(channelID string, timestamp int
|
||||
return result, resultVar1, err
|
||||
}
|
||||
|
||||
func (s *TimerLayerChannelStore) CountUrgentPostsAfter(channelID string, timestamp int64, userID string) (int, error) {
|
||||
start := time.Now()
|
||||
|
||||
result, err := s.ChannelStore.CountUrgentPostsAfter(channelID, timestamp, userID)
|
||||
|
||||
elapsed := float64(time.Since(start)) / float64(time.Second)
|
||||
if s.Root.Metrics != nil {
|
||||
success := "false"
|
||||
if err == nil {
|
||||
success = "true"
|
||||
}
|
||||
s.Root.Metrics.ObserveStoreMethodDuration("ChannelStore.CountUrgentPostsAfter", success, elapsed)
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (s *TimerLayerChannelStore) CreateDirectChannel(userID *model.User, otherUserID *model.User, channelOptions ...model.ChannelOption) (*model.Channel, error) {
|
||||
start := time.Now()
|
||||
|
||||
@@ -1711,10 +1737,10 @@ func (s *TimerLayerChannelStore) GroupSyncedChannelCount() (int64, error) {
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (s *TimerLayerChannelStore) IncrementMentionCount(channelID string, userIDs []string, isRoot bool) error {
|
||||
func (s *TimerLayerChannelStore) IncrementMentionCount(channelID string, userIDs []string, isRoot bool, isUrgent bool) error {
|
||||
start := time.Now()
|
||||
|
||||
err := s.ChannelStore.IncrementMentionCount(channelID, userIDs, isRoot)
|
||||
err := s.ChannelStore.IncrementMentionCount(channelID, userIDs, isRoot, isUrgent)
|
||||
|
||||
elapsed := float64(time.Since(start)) / float64(time.Second)
|
||||
if s.Root.Metrics != nil {
|
||||
@@ -2248,10 +2274,10 @@ func (s *TimerLayerChannelStore) UpdateLastViewedAt(channelIds []string, userID
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (s *TimerLayerChannelStore) UpdateLastViewedAtPost(unreadPost *model.Post, userID string, mentionCount int, mentionCountRoot int, setUnreadCountRoot bool) (*model.ChannelUnreadAt, error) {
|
||||
func (s *TimerLayerChannelStore) UpdateLastViewedAtPost(unreadPost *model.Post, userID string, mentionCount int, mentionCountRoot int, urgentMentionCount int, setUnreadCountRoot bool) (*model.ChannelUnreadAt, error) {
|
||||
start := time.Now()
|
||||
|
||||
result, err := s.ChannelStore.UpdateLastViewedAtPost(unreadPost, userID, mentionCount, mentionCountRoot, setUnreadCountRoot)
|
||||
result, err := s.ChannelStore.UpdateLastViewedAtPost(unreadPost, userID, mentionCount, mentionCountRoot, urgentMentionCount, setUnreadCountRoot)
|
||||
|
||||
elapsed := float64(time.Since(start)) / float64(time.Second)
|
||||
if s.Root.Metrics != nil {
|
||||
@@ -5891,6 +5917,38 @@ func (s *TimerLayerPostStore) Update(newPost *model.Post, oldPost *model.Post) (
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (s *TimerLayerPostPriorityStore) GetForPost(postId string) (*model.PostPriority, error) {
|
||||
start := time.Now()
|
||||
|
||||
result, err := s.PostPriorityStore.GetForPost(postId)
|
||||
|
||||
elapsed := float64(time.Since(start)) / float64(time.Second)
|
||||
if s.Root.Metrics != nil {
|
||||
success := "false"
|
||||
if err == nil {
|
||||
success = "true"
|
||||
}
|
||||
s.Root.Metrics.ObserveStoreMethodDuration("PostPriorityStore.GetForPost", success, elapsed)
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (s *TimerLayerPostPriorityStore) GetForPosts(ids []string) ([]*model.PostPriority, error) {
|
||||
start := time.Now()
|
||||
|
||||
result, err := s.PostPriorityStore.GetForPosts(ids)
|
||||
|
||||
elapsed := float64(time.Since(start)) / float64(time.Second)
|
||||
if s.Root.Metrics != nil {
|
||||
success := "false"
|
||||
if err == nil {
|
||||
success = "true"
|
||||
}
|
||||
s.Root.Metrics.ObserveStoreMethodDuration("PostPriorityStore.GetForPosts", success, elapsed)
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (s *TimerLayerPreferenceStore) CleanupFlagsBatch(limit int64) (int64, error) {
|
||||
start := time.Now()
|
||||
|
||||
@@ -8881,10 +8939,10 @@ func (s *TimerLayerThreadStore) GetMembershipsForUser(userId string, teamID stri
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (s *TimerLayerThreadStore) GetTeamsUnreadForUser(userID string, teamIDs []string) (map[string]*model.TeamUnread, error) {
|
||||
func (s *TimerLayerThreadStore) GetTeamsUnreadForUser(userID string, teamIDs []string, includeUrgentMentionCount bool) (map[string]*model.TeamUnread, error) {
|
||||
start := time.Now()
|
||||
|
||||
result, err := s.ThreadStore.GetTeamsUnreadForUser(userID, teamIDs)
|
||||
result, err := s.ThreadStore.GetTeamsUnreadForUser(userID, teamIDs, includeUrgentMentionCount)
|
||||
|
||||
elapsed := float64(time.Since(start)) / float64(time.Second)
|
||||
if s.Root.Metrics != nil {
|
||||
@@ -8913,10 +8971,10 @@ func (s *TimerLayerThreadStore) GetThreadFollowers(threadID string, fetchOnlyAct
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (s *TimerLayerThreadStore) GetThreadForUser(threadMembership *model.ThreadMembership, extended bool) (*model.ThreadResponse, error) {
|
||||
func (s *TimerLayerThreadStore) GetThreadForUser(threadMembership *model.ThreadMembership, extended bool, postPriorityIsEnabled bool) (*model.ThreadResponse, error) {
|
||||
start := time.Now()
|
||||
|
||||
result, err := s.ThreadStore.GetThreadForUser(threadMembership, extended)
|
||||
result, err := s.ThreadStore.GetThreadForUser(threadMembership, extended, postPriorityIsEnabled)
|
||||
|
||||
elapsed := float64(time.Since(start)) / float64(time.Second)
|
||||
if s.Root.Metrics != nil {
|
||||
@@ -9041,6 +9099,22 @@ func (s *TimerLayerThreadStore) GetTotalUnreadThreads(userId string, teamID stri
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (s *TimerLayerThreadStore) GetTotalUnreadUrgentMentions(userId string, teamID string, opts model.GetUserThreadsOpts) (int64, error) {
|
||||
start := time.Now()
|
||||
|
||||
result, err := s.ThreadStore.GetTotalUnreadUrgentMentions(userId, teamID, opts)
|
||||
|
||||
elapsed := float64(time.Since(start)) / float64(time.Second)
|
||||
if s.Root.Metrics != nil {
|
||||
success := "false"
|
||||
if err == nil {
|
||||
success = "true"
|
||||
}
|
||||
s.Root.Metrics.ObserveStoreMethodDuration("ThreadStore.GetTotalUnreadUrgentMentions", success, elapsed)
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (s *TimerLayerThreadStore) MaintainMembership(userID string, postID string, opts store.ThreadMembershipOpts) (*model.ThreadMembership, error) {
|
||||
start := time.Now()
|
||||
|
||||
@@ -11270,6 +11344,7 @@ func New(childStore store.Store, metrics einterfaces.MetricsInterface) *TimerLay
|
||||
newStore.OAuthStore = &TimerLayerOAuthStore{OAuthStore: childStore.OAuth(), Root: &newStore}
|
||||
newStore.PluginStore = &TimerLayerPluginStore{PluginStore: childStore.Plugin(), Root: &newStore}
|
||||
newStore.PostStore = &TimerLayerPostStore{PostStore: childStore.Post(), Root: &newStore}
|
||||
newStore.PostPriorityStore = &TimerLayerPostPriorityStore{PostPriorityStore: childStore.PostPriority(), Root: &newStore}
|
||||
newStore.PreferenceStore = &TimerLayerPreferenceStore{PreferenceStore: childStore.Preference(), Root: &newStore}
|
||||
newStore.ProductNoticesStore = &TimerLayerProductNoticesStore{ProductNoticesStore: childStore.ProductNotices(), Root: &newStore}
|
||||
newStore.ReactionStore = &TimerLayerReactionStore{ReactionStore: childStore.Reaction(), Root: &newStore}
|
||||
|
||||
Ссылка в новой задаче
Block a user