[MM-37933] Channel preference to auto-follow all threads in the channel (#21430)

* Add auto-follow feature
---------

Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
Co-authored-by: Mattermost Build <build@mattermost.com>
Этот коммит содержится в:
Vishal
2023-05-05 12:09:00 +05:30
коммит произвёл GitHub
родитель 9f11fc59b5
Коммит d860548a76
23 изменённых файлов: 299 добавлений и 14 удалений

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

@@ -1354,6 +1354,10 @@ func (a *App) UpdateChannelMemberNotifyProps(c request.CTX, data map[string]stri
filteredProps[model.IgnoreChannelMentionsNotifyProp] = ignoreChannelMentions
}
if channelAutoFollowThreads, exists := data[model.ChannelAutoFollowThreads]; exists {
filteredProps[model.ChannelAutoFollowThreads] = channelAutoFollowThreads
}
member, err := a.Srv().Store().Channel().UpdateMemberNotifyProps(channelID, userID, filteredProps)
if err != nil {
var appErr *model.AppError

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

@@ -101,13 +101,15 @@ func (a *App) SendNotifications(c request.CTX, post *model.Post, team *model.Tea
}
channelMemberNotifyPropsMap := result.Data.(map[string]model.StringMap)
followers := make(model.StringArray, 0)
followers := make(model.StringSet, 0)
if tchan != nil {
result = <-tchan
if result.NErr != nil {
return nil, result.NErr
}
followers = result.Data.([]string)
for _, v := range result.Data.([]string) {
followers.Add(v)
}
}
groups := make(map[string]*model.Group)
@@ -235,6 +237,14 @@ func (a *App) SendNotifications(c request.CTX, post *model.Post, team *model.Tea
threadParticipants[id] = true
}
if channel.Type != model.ChannelTypeDirect {
for id, propsMap := range channelMemberNotifyPropsMap {
if ok := followers.Has(id); !ok && propsMap[model.ChannelAutoFollowThreads] == model.ChannelAutoFollowThreadsOn {
threadParticipants[id] = true
}
}
}
// sema is a counting semaphore to throttle the number of concurrent DB requests.
// A concurrency of 8 should be sufficient.
// We don't want to set a higher limit which can bring down the DB.
@@ -286,8 +296,8 @@ func (a *App) SendNotifications(c request.CTX, post *model.Post, team *model.Tea
followersMutex.Lock()
// add new followers to existing followers
if threadMembership.Following && !followers.Contains(userID) {
followers = append(followers, userID)
if ok := followers.Has(userID); !ok && threadMembership.Following {
followers.Add(userID)
newParticipants[userID] = true
}
followersMutex.Unlock()
@@ -330,7 +340,7 @@ func (a *App) SendNotifications(c request.CTX, post *model.Post, team *model.Tea
notificationsForCRT := &CRTNotifiers{}
if isCRTAllowed && post.RootId != "" {
for _, uid := range followers {
for uid := range followers {
profile := profileMap[uid]
if profile == nil || !a.IsCRTEnabledForUser(c, uid) {
continue
@@ -578,7 +588,7 @@ func (a *App) SendNotifications(c request.CTX, post *model.Post, team *model.Tea
// If this is a reply in a thread, notify participants
if isCRTAllowed && post.RootId != "" {
for _, uid := range followers {
for uid := range followers {
// A user following a thread but had left the channel won't get a notification
// https://mattermost.atlassian.net/browse/MM-36769
if profileMap[uid] == nil {

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

@@ -10,6 +10,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/mattermost/mattermost-server/server/v8/channels/store"
"github.com/mattermost/mattermost-server/server/v8/channels/utils"
"github.com/mattermost/mattermost-server/server/v8/model"
"github.com/mattermost/mattermost-server/server/v8/platform/shared/i18n"
@@ -2819,3 +2820,66 @@ func TestReplyPostNotificationsWithCRT(t *testing.T) {
assert.Nil(t, membership)
})
}
func TestChannelAutoFollowThreads(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
u1 := th.BasicUser
u2 := th.BasicUser2
u3 := th.CreateUser()
th.LinkUserToTeam(u3, th.BasicTeam)
c1 := th.BasicChannel
th.AddUserToChannel(u2, c1)
th.AddUserToChannel(u3, c1)
// Set auto-follow for user 2
member, appErr := th.App.UpdateChannelMemberNotifyProps(th.Context, map[string]string{model.ChannelAutoFollowThreads: model.ChannelAutoFollowThreadsOn}, c1.Id, u2.Id)
require.Nil(t, appErr)
require.Equal(t, model.ChannelAutoFollowThreadsOn, member.NotifyProps[model.ChannelAutoFollowThreads])
rootPost := &model.Post{
ChannelId: c1.Id,
Message: "root post by user3",
UserId: u3.Id,
}
rpost, appErr := th.App.CreatePost(th.Context, rootPost, c1, false, true)
require.Nil(t, appErr)
replyPost1 := &model.Post{
ChannelId: c1.Id,
Message: "reply post by user1",
UserId: u1.Id,
RootId: rpost.Id,
}
_, appErr = th.App.CreatePost(th.Context, replyPost1, c1, false, true)
require.Nil(t, appErr)
// user-2 starts auto-following thread
threadMembership, appErr := th.App.GetThreadMembershipForUser(u2.Id, rpost.Id)
require.Nil(t, appErr)
require.NotNil(t, threadMembership)
assert.True(t, threadMembership.Following)
// Set "following" to false
_, err := th.App.Srv().Store().Thread().MaintainMembership(u2.Id, rpost.Id, store.ThreadMembershipOpts{
Following: false,
UpdateFollowing: true,
})
require.NoError(t, err)
replyPost2 := &model.Post{
ChannelId: c1.Id,
Message: "reply post 2 by user1",
UserId: u1.Id,
RootId: rpost.Id,
}
_, appErr = th.App.CreatePost(th.Context, replyPost2, c1, false, true)
require.Nil(t, appErr)
// Do NOT start auto-following thread, once "un-followed"
threadMembership, appErr = th.App.GetThreadMembershipForUser(u2.Id, rpost.Id)
require.Nil(t, appErr)
require.NotNil(t, threadMembership)
assert.False(t, threadMembership.Following)
}