optionally exclude threads in direct messages (#29042)

* optionally exclude threads in direct messages

* add excludeDirect option in client4

* Skip flaky test

* refactor double negate

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
Этот коммит содержится в:
Elias Nahum
2024-11-14 16:57:15 +08:00
коммит произвёл GitHub
родитель 38e2f67583
Коммит 701d1dbd68
6 изменённых файлов: 69 добавлений и 24 удалений

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

@@ -972,6 +972,7 @@ func TestUpdateChannelBookmarkSortOrder(t *testing.T) {
}) })
t.Run("a websockets event should be fired as part of editing a bookmark's sort order", func(t *testing.T) { t.Run("a websockets event should be fired as part of editing a bookmark's sort order", func(t *testing.T) {
t.Skip("MM-61301")
now := model.GetMillis() now := model.GetMillis()
webSocketClient, err := th.CreateWebSocketClient() webSocketClient, err := th.CreateWebSocketClient()
require.NoError(t, err) require.NoError(t, err)

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

@@ -3290,8 +3290,10 @@ func getThreadsForUser(c *Context, w http.ResponseWriter, r *http.Request) {
options.After = r.URL.Query().Get("after") options.After = r.URL.Query().Get("after")
totalsOnlyStr := r.URL.Query().Get("totalsOnly") totalsOnlyStr := r.URL.Query().Get("totalsOnly")
threadsOnlyStr := r.URL.Query().Get("threadsOnly") threadsOnlyStr := r.URL.Query().Get("threadsOnly")
excludeDirectStr := r.URL.Query().Get("excludeDirect")
options.TotalsOnly, _ = strconv.ParseBool(totalsOnlyStr) options.TotalsOnly, _ = strconv.ParseBool(totalsOnlyStr)
options.ThreadsOnly, _ = strconv.ParseBool(threadsOnlyStr) options.ThreadsOnly, _ = strconv.ParseBool(threadsOnlyStr)
options.ExcludeDirect, _ = strconv.ParseBool(excludeDirectStr)
// parameters are mutually exclusive // parameters are mutually exclusive
if options.Before != "" && options.After != "" { if options.Before != "" && options.After != "" {

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

@@ -134,11 +134,16 @@ func (s *SqlThreadStore) getTotalThreadsQuery(userId, teamId string, opts model.
}) })
if teamId != "" { if teamId != "" {
query = query. if opts.ExcludeDirect {
Where(sq.Or{ query = query.Where(sq.Eq{"Threads.ThreadTeamId": teamId})
sq.Eq{"Threads.ThreadTeamId": teamId}, } else {
sq.Eq{"Threads.ThreadTeamId": ""}, query = query.Where(
}) sq.Or{
sq.Eq{"Threads.ThreadTeamId": teamId},
sq.Eq{"Threads.ThreadTeamId": ""},
},
)
}
} }
if !opts.Deleted { if !opts.Deleted {
@@ -196,11 +201,16 @@ func (s *SqlThreadStore) GetTotalUnreadMentions(userId, teamId string, opts mode
}) })
if teamId != "" { if teamId != "" {
query = query. if opts.ExcludeDirect {
Where(sq.Or{ query = query.Where(sq.Eq{"Threads.ThreadTeamId": teamId})
sq.Eq{"Threads.ThreadTeamId": teamId}, } else {
sq.Eq{"Threads.ThreadTeamId": ""}, query = query.Where(
}) sq.Or{
sq.Eq{"Threads.ThreadTeamId": teamId},
sq.Eq{"Threads.ThreadTeamId": ""},
},
)
}
} }
if !opts.Deleted { if !opts.Deleted {
@@ -235,11 +245,16 @@ func (s *SqlThreadStore) GetTotalUnreadUrgentMentions(userId, teamId string, opt
} }
if teamId != "" { if teamId != "" {
query = query. if opts.ExcludeDirect {
Where(sq.Or{ query = query.Where(sq.Eq{"Threads.ThreadTeamId": teamId})
sq.Eq{"Threads.ThreadTeamId": teamId}, } else {
sq.Eq{"Threads.ThreadTeamId": ""}, query = query.Where(
}) sq.Or{
sq.Eq{"Threads.ThreadTeamId": teamId},
sq.Eq{"Threads.ThreadTeamId": ""},
},
)
}
} }
if !opts.Deleted { if !opts.Deleted {
@@ -296,14 +311,19 @@ func (s *SqlThreadStore) GetThreadsForUser(userId, teamId string, opts model.Get
LeftJoin("PostsPriority ON PostsPriority.PostId = Threads.PostId") LeftJoin("PostsPriority ON PostsPriority.PostId = Threads.PostId")
} }
// If a team is specified, constrain to channels in that team or DMs/GMs without // If a team is specified, constrain to channels in that team and if not excluded also return DMs/GMs without
// a team at all. // a team at all.
if teamId != "" { if teamId != "" {
query = query. if opts.ExcludeDirect {
Where(sq.Or{ query = query.Where(sq.Eq{"Threads.ThreadTeamId": teamId})
sq.Eq{"Threads.ThreadTeamId": teamId}, } else {
sq.Eq{"Threads.ThreadTeamId": ""}, query = query.Where(
}) sq.Or{
sq.Eq{"Threads.ThreadTeamId": teamId},
sq.Eq{"Threads.ThreadTeamId": ""},
},
)
}
} }
if !opts.Deleted { if !opts.Deleted {

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

@@ -916,6 +916,13 @@ func testVarious(t *testing.T, rctx request.CTX, ss store.Store) {
ChannelId: gm1.Id, ChannelId: gm1.Id,
UserId: user1ID, UserId: user1ID,
Message: model.NewRandomString(10), Message: model.NewRandomString(10),
Metadata: &model.PostMetadata{
Priority: &model.PostPriority{
Priority: model.NewPointer(model.PostPriorityUrgent),
RequestedAck: model.NewPointer(false),
PersistentNotifications: model.NewPointer(false),
},
},
}) })
require.NoError(t, err) require.NoError(t, err)
@@ -1077,6 +1084,9 @@ func testVarious(t *testing.T, rctx request.CTX, ss store.Store) {
{"team2, user1", user1ID, team2.Id, model.GetUserThreadsOpts{}, []*model.Post{ {"team2, user1", user1ID, team2.Id, model.GetUserThreadsOpts{}, []*model.Post{
gm1post1, gm1post1,
}}, }},
{"team1, user1, exclude direct", user1ID, team1.Id, model.GetUserThreadsOpts{ExcludeDirect: true}, []*model.Post{
team1channel1post3,
}},
} }
for _, testCase := range testCases { for _, testCase := range testCases {
@@ -1098,12 +1108,13 @@ func testVarious(t *testing.T, rctx request.CTX, ss store.Store) {
ExpectedThreads []*model.Post ExpectedThreads []*model.Post
}{ }{
{"all teams, user1", user1ID, "", model.GetUserThreadsOpts{}, []*model.Post{ {"all teams, user1", user1ID, "", model.GetUserThreadsOpts{}, []*model.Post{
team1channel1post3, team1channel1post3, gm1post1,
}}, }},
{"team1, user1", user1ID, team1.Id, model.GetUserThreadsOpts{}, []*model.Post{ {"team1, user1", user1ID, team1.Id, model.GetUserThreadsOpts{}, []*model.Post{
team1channel1post3, team1channel1post3, gm1post1,
}}, }},
{"team2, user1", user1ID, team2.Id, model.GetUserThreadsOpts{}, []*model.Post{}}, {"team2, user1", user1ID, team2.Id, model.GetUserThreadsOpts{}, []*model.Post{gm1post1}},
{"team1, user1, exclude direct", user1ID, team2.Id, model.GetUserThreadsOpts{}, []*model.Post{team1channel1post3}},
} }
for _, testCase := range testCases { for _, testCase := range testCases {
@@ -1183,6 +1194,9 @@ func testVarious(t *testing.T, rctx request.CTX, ss store.Store) {
{"team2, user1", user1ID, team2.Id, model.GetUserThreadsOpts{}, []*model.Post{ {"team2, user1", user1ID, team2.Id, model.GetUserThreadsOpts{}, []*model.Post{
team2channel1post1, dm1post1, gm1post1, team2channel1post1, dm1post1, gm1post1,
}}, }},
{"team2, user1, exclude direct", user1ID, team2.Id, model.GetUserThreadsOpts{ExcludeDirect: true}, []*model.Post{
team2channel1post1,
}},
{"team2, user1, unread", user1ID, team2.Id, model.GetUserThreadsOpts{Unread: true}, []*model.Post{ {"team2, user1, unread", user1ID, team2.Id, model.GetUserThreadsOpts{Unread: true}, []*model.Post{
gm1post1, // (no unread in team2) gm1post1, // (no unread in team2)
}}, }},
@@ -1192,6 +1206,9 @@ func testVarious(t *testing.T, rctx request.CTX, ss store.Store) {
{"team2, user1, unread + deleted", user1ID, team2.Id, model.GetUserThreadsOpts{Unread: true, Deleted: true}, []*model.Post{ {"team2, user1, unread + deleted", user1ID, team2.Id, model.GetUserThreadsOpts{Unread: true, Deleted: true}, []*model.Post{
team2channel1post2deleted, gm1post1, team2channel1post2deleted, gm1post1,
}}, }},
{"team2, user1, unread + deleted + exclude direct", user1ID, team2.Id, model.GetUserThreadsOpts{Unread: true, Deleted: true, ExcludeDirect: true}, []*model.Post{
team2channel1post2deleted,
}},
} }
for _, testCase := range testCases { for _, testCase := range testCases {

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

@@ -8724,6 +8724,9 @@ func (c *Client4) GetUserThreads(ctx context.Context, userId, teamId string, opt
if options.TotalsOnly { if options.TotalsOnly {
v.Set("totalsOnly", "true") v.Set("totalsOnly", "true")
} }
if options.ExcludeDirect {
v.Set("excludeDirect", fmt.Sprintf("%t", options.ExcludeDirect))
}
url := c.userThreadsRoute(userId, teamId) url := c.userThreadsRoute(userId, teamId)
if len(v) > 0 { if len(v) > 0 {
url += "?" + v.Encode() url += "?" + v.Encode()

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

@@ -88,6 +88,8 @@ type GetUserThreadsOpts struct {
// IncludeIsUrgent will return IsUrgent field as well to assert is the thread is urgent or not // IncludeIsUrgent will return IsUrgent field as well to assert is the thread is urgent or not
IncludeIsUrgent bool IncludeIsUrgent bool
ExcludeDirect bool
} }
func (o *Thread) Etag() string { func (o *Thread) Etag() string {