MM-30970 Add Basic unreadMentions support for collapsed threads (#16407)

Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
Этот коммит содержится в:
Eli Yukelzon
2020-12-01 17:20:23 +02:00
коммит произвёл GitHub
родитель 1bd7dc41bd
Коммит c2036f614e
14 изменённых файлов: 330 добавлений и 66 удалений

Просмотреть файл

@@ -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

Просмотреть файл

@@ -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) {

Просмотреть файл

@@ -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)