MM-17071 Add mention counting when marking a post as unread (#11966)

* Add different types for different mentions

* Remove redundant THREAD_ANY and THREAD_ROOT constants

* Make PostStore.Get return thread in order

* MM-17071 Add initial version of countMentionsFromPost

* MM-17071 Refactor comment mention counting

* MM-17071 Use mention counting when marking post as unread

* Fix shadowing in tests

* Remove repeated check of user count

* Refactor code using MentionType

* Update comments around -1 return value

* Move inner functions out of countMentionsFromPost

* Remove preconditions check as separate test case

* Update comments

* Add User.GetMentionKeys

* Revert "Make PostStore.Get return thread in order"

This reverts commit 22aa010cee359655fe75e1dc899cf0ffb0943c2a.

* Fix tests

* Fix merge conflict

* Add store.MentionAllPosts
Этот коммит содержится в:
Harrison Healey
2019-09-19 10:10:10 -04:00
коммит произвёл GitHub
родитель 5f28ce9de0
Коммит e6f67c664c
11 изменённых файлов: 1457 добавлений и 415 удалений

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

@@ -1178,3 +1178,137 @@ func (a *App) MaxPostSize() int {
return maxPostSize
}
// countMentionsFromPost returns the number of posts in the post's channel that mention the user after and including the
// given post. Returns the number of mentions or store.MentionAllPosts if the post is in a direct message channel.
func (a *App) countMentionsFromPost(user *model.User, post *model.Post) (int, *model.AppError) {
channel, err := a.GetChannel(post.ChannelId)
if err != nil {
return 0, err
}
if channel.Type == model.CHANNEL_DIRECT {
return store.MentionAllPosts, nil
}
channelMember, err := a.GetChannelMember(channel.Id, user.Id)
if err != nil {
return 0, err
}
keywords := addMentionKeywordsForUser(
map[string][]string{},
user,
channelMember.NotifyProps,
&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
)
commentMentions := user.NotifyProps[model.COMMENTS_NOTIFY_PROP]
checkForCommentMentions := commentMentions == model.COMMENTS_NOTIFY_ROOT || commentMentions == model.COMMENTS_NOTIFY_ANY
// A mapping of thread root IDs to whether or not a post in that thread mentions the user
mentionedByThread := make(map[string]bool)
thread, err := a.GetPostThread(post.Id)
if err != nil {
return 0, err
}
count := 0
if isPostMention(user, post, keywords, thread.Posts, mentionedByThread, checkForCommentMentions) {
count += 1
}
page := 0
perPage := 200
for {
postList, err := a.GetPostsAfterPost(model.GetPostsOptions{
ChannelId: post.ChannelId,
PostId: post.Id,
Page: page,
PerPage: perPage,
})
if err != nil {
return 0, err
}
for _, postId := range postList.Order {
if isPostMention(user, postList.Posts[postId], keywords, postList.Posts, mentionedByThread, checkForCommentMentions) {
count += 1
}
}
if len(postList.Order) < perPage {
break
}
page += 1
}
return count, nil
}
func isCommentMention(user *model.User, post *model.Post, otherPosts map[string]*model.Post, mentionedByThread map[string]bool) bool {
if post.RootId == "" {
// Not a comment
return false
}
if mentioned, ok := mentionedByThread[post.RootId]; ok {
// We've already figured out if the user was mentioned by this thread
return mentioned
}
// Whether or not the user was mentioned because they started the thread
mentioned := otherPosts[post.RootId].UserId == user.Id
// Or because they commented on it before this post
if !mentioned && user.NotifyProps[model.COMMENTS_NOTIFY_PROP] == model.COMMENTS_NOTIFY_ANY {
for _, otherPost := range otherPosts {
if otherPost.Id == post.Id {
continue
}
if otherPost.RootId != post.RootId {
continue
}
if otherPost.UserId == user.Id && otherPost.CreateAt < post.CreateAt {
// Found a comment made by the user from before this post
mentioned = true
break
}
}
}
mentionedByThread[post.RootId] = mentioned
return mentioned
}
func isPostMention(user *model.User, post *model.Post, keywords map[string][]string, otherPosts map[string]*model.Post, mentionedByThread map[string]bool, checkForCommentMentions bool) bool {
// Prevent the user from mentioning themselves
if post.UserId == user.Id && post.Props["from_webhook"] != "true" {
return false
}
// Check for keyword mentions
mentions := getExplicitMentions(post, keywords)
if _, ok := mentions.Mentions[user.Id]; ok {
return true
}
// Check for mentions caused by being added to the channel
if post.Type == model.POST_ADD_TO_CHANNEL {
if addedUserId, ok := post.Props[model.POST_PROPS_ADDED_USER_ID].(string); ok && addedUserId == user.Id {
return true
}
}
// Check for comment mentions
if checkForCommentMentions && isCommentMention(user, post, otherPosts, mentionedByThread) {
return true
}
return false
}