MM-30970 Add Basic unreadMentions support for collapsed threads (#16407)
Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
1bd7dc41bd
Коммит
c2036f614e
@@ -2337,6 +2337,24 @@ func (a *App) MarkChannelAsUnreadFromPost(postID string, userID string) (*model.
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if *a.Config().ServiceSettings.ThreadAutoFollow && post.RootId != "" {
|
||||
threadMembership, _ := a.Srv().Store.Thread().GetMembershipForUser(user.Id, post.RootId)
|
||||
if threadMembership != nil {
|
||||
channel, nErr := a.Srv().Store.Channel().Get(post.ChannelId, true)
|
||||
if nErr != nil {
|
||||
return nil, model.NewAppError("MarkChannelAsUnreadFromPost", "app.channel.update_last_viewed_at_post.app_error", nil, nErr.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
threadMembership.UnreadMentions, err = a.countThreadMentions(user, post, channel.TeamId, post.UpdateAt-1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, nErr = a.Srv().Store.Thread().UpdateMembership(threadMembership)
|
||||
if nErr != nil {
|
||||
return nil, model.NewAppError("MarkChannelAsUnreadFromPost", "app.channel.update_last_viewed_at_post.app_error", nil, nErr.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
channelUnread, nErr := a.Srv().Store.Channel().UpdateLastViewedAtPost(post, userID, unreadMentions, *a.Config().ServiceSettings.ThreadAutoFollow)
|
||||
if nErr != nil {
|
||||
return channelUnread, model.NewAppError("MarkChannelAsUnreadFromPost", "app.channel.update_last_viewed_at_post.app_error", nil, nErr.Error(), http.StatusInternalServerError)
|
||||
|
||||
@@ -162,21 +162,27 @@ func (a *App) SendNotifications(post *model.Post, team *model.Team, channel *mod
|
||||
mentionedUsersList := make([]string, 0, len(mentions.Mentions))
|
||||
updateMentionChans := []chan *model.AppError{}
|
||||
mentionAutofollowChans := []chan *model.AppError{}
|
||||
threadParticipants := []string{post.UserId}
|
||||
threadParticipants := map[string]bool{post.UserId: true}
|
||||
if *a.Config().ServiceSettings.ThreadAutoFollow && post.RootId != "" {
|
||||
if parentPostList != nil {
|
||||
threadParticipants = append(threadParticipants, parentPostList.Posts[parentPostList.Order[0]].UserId)
|
||||
threadParticipants[parentPostList.Posts[parentPostList.Order[0]].UserId] = true
|
||||
}
|
||||
for id := range mentions.Mentions {
|
||||
threadParticipants = append(threadParticipants, id)
|
||||
threadParticipants[id] = true
|
||||
}
|
||||
// for each mention, make sure to update thread autofollow
|
||||
for _, id := range threadParticipants {
|
||||
// for each mention, make sure to update thread autofollow (if enabled) and update increment mention count
|
||||
for id := range threadParticipants {
|
||||
mac := make(chan *model.AppError, 1)
|
||||
go func(userId string) {
|
||||
defer close(mac)
|
||||
|
||||
nErr := a.Srv().Store.Thread().CreateMembershipIfNeeded(userId, post.RootId, true)
|
||||
incrementMentions := false
|
||||
for mid := range mentions.Mentions {
|
||||
if userId == mid {
|
||||
incrementMentions = true
|
||||
break
|
||||
}
|
||||
}
|
||||
nErr := a.Srv().Store.Thread().CreateMembershipIfNeeded(userId, post.RootId, true, incrementMentions, *a.Config().ServiceSettings.ThreadAutoFollow)
|
||||
if nErr != nil {
|
||||
mac <- model.NewAppError("SendNotifications", "app.channel.autofollow.app_error", nil, nErr.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
|
||||
60
app/post.go
60
app/post.go
@@ -458,7 +458,7 @@ func (a *App) handlePostEvents(post *model.Post, user *model.User, channel *mode
|
||||
}
|
||||
|
||||
if *a.Config().ServiceSettings.ThreadAutoFollow && post.RootId != "" {
|
||||
if err := a.Srv().Store.Thread().CreateMembershipIfNeeded(post.UserId, post.RootId, true); err != nil {
|
||||
if err := a.Srv().Store.Thread().CreateMembershipIfNeeded(post.UserId, post.RootId, true, false, true); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -1340,6 +1340,64 @@ func (a *App) MaxPostSize() int {
|
||||
return a.Srv().MaxPostSize()
|
||||
}
|
||||
|
||||
// countThreadMentions returns the number of times the user is mentioned in a specified thread after the timestamp.
|
||||
func (a *App) countThreadMentions(user *model.User, post *model.Post, teamId string, timestamp int64) (int64, *model.AppError) {
|
||||
team, err := a.GetTeam(teamId)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
channel, err := a.GetChannel(post.ChannelId)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
keywords := addMentionKeywordsForUser(
|
||||
map[string][]string{},
|
||||
user,
|
||||
map[string]string{},
|
||||
&model.Status{Status: model.STATUS_ONLINE}, // Assume the user is online since they would've triggered this
|
||||
true, // Assume channel mentions are always allowed for simplicity
|
||||
)
|
||||
|
||||
posts, nErr := a.Srv().Store.Thread().GetPosts(post.Id, timestamp)
|
||||
if nErr != nil {
|
||||
return 0, model.NewAppError("countMentionsFromPost", "app.channel.count_posts_since.app_error", nil, nErr.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
count := 0
|
||||
|
||||
if channel.Type == model.CHANNEL_DIRECT {
|
||||
// In a DM channel, every post made by the other user is a mention
|
||||
otherId := channel.GetOtherUserIdForDM(user.Id)
|
||||
for _, p := range posts {
|
||||
if p.UserId == otherId {
|
||||
count++
|
||||
}
|
||||
}
|
||||
|
||||
return int64(count), nil
|
||||
}
|
||||
|
||||
groups, nErr := a.getGroupsAllowedForReferenceInChannel(channel, team)
|
||||
if nErr != nil {
|
||||
return 0, model.NewAppError("countMentionsFromPost", "app.channel.count_posts_since.app_error", nil, nErr.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
mentions := getExplicitMentions(post, keywords, groups)
|
||||
if _, ok := mentions.Mentions[user.Id]; ok {
|
||||
count += 1
|
||||
}
|
||||
|
||||
for _, p := range posts {
|
||||
mentions = getExplicitMentions(p, keywords, groups)
|
||||
if _, ok := mentions.Mentions[user.Id]; ok {
|
||||
count += 1
|
||||
}
|
||||
}
|
||||
|
||||
return int64(count), nil
|
||||
}
|
||||
|
||||
// countMentionsFromPost returns the number of posts in the post's channel that mention the user after and including the
|
||||
// given post.
|
||||
func (a *App) countMentionsFromPost(user *model.User, post *model.Post) (int, *model.AppError) {
|
||||
|
||||
14
app/user.go
14
app/user.go
@@ -2384,9 +2384,9 @@ func (a *App) GetThreadsForUser(userId string, options model.GetUserThreadsOpts)
|
||||
}
|
||||
|
||||
func (a *App) UpdateThreadsReadForUser(userId string, timestamp int64) *model.AppError {
|
||||
err := a.Srv().Store.Thread().MarkAllAsRead(userId, timestamp)
|
||||
if err != nil {
|
||||
return model.NewAppError("UpdateThreadsReadForUser", "app.user.update_threads_read_for_user.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
nErr := a.Srv().Store.Thread().MarkAllAsRead(userId, timestamp)
|
||||
if nErr != nil {
|
||||
return model.NewAppError("UpdateThreadsReadForUser", "app.user.update_threads_read_for_user.app_error", nil, nErr.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_THREAD_READ_CHANGED, "", "", userId, nil)
|
||||
message.Add("timestamp", timestamp)
|
||||
@@ -2395,7 +2395,7 @@ func (a *App) UpdateThreadsReadForUser(userId string, timestamp int64) *model.Ap
|
||||
}
|
||||
|
||||
func (a *App) UpdateThreadFollowForUser(userId, threadId string, state bool) *model.AppError {
|
||||
err := a.Srv().Store.Thread().CreateMembershipIfNeeded(userId, threadId, state)
|
||||
err := a.Srv().Store.Thread().CreateMembershipIfNeeded(userId, threadId, state, false, true)
|
||||
if err != nil {
|
||||
return model.NewAppError("UpdateThreadFollowForUser", "app.user.update_thread_follow_for_user.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
@@ -2407,9 +2407,9 @@ func (a *App) UpdateThreadFollowForUser(userId, threadId string, state bool) *mo
|
||||
}
|
||||
|
||||
func (a *App) UpdateThreadReadForUser(userId, threadId string, timestamp int64) *model.AppError {
|
||||
err := a.Srv().Store.Thread().MarkAsRead(userId, threadId, timestamp)
|
||||
if err != nil {
|
||||
return model.NewAppError("UpdateThreadReadForUser", "app.user.update_thread_read_for_user.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
nErr := a.Srv().Store.Thread().MarkAsRead(userId, threadId, timestamp)
|
||||
if nErr != nil {
|
||||
return model.NewAppError("UpdateThreadReadForUser", "app.user.update_thread_read_for_user.app_error", nil, nErr.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_THREAD_READ_CHANGED, "", "", userId, nil)
|
||||
message.Add("thread_id", threadId)
|
||||
|
||||
Ссылка в новой задаче
Block a user