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>
This commit is contained in:
Elias Nahum 2024-11-14 16:57:15 +08:00 committed by GitHub
parent 38e2f67583
commit 701d1dbd68
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 69 additions and 24 deletions

View file

@ -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.Skip("MM-61301")
now := model.GetMillis()
webSocketClient, err := th.CreateWebSocketClient()
require.NoError(t, err)

View file

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

View file

@ -134,11 +134,16 @@ func (s *SqlThreadStore) getTotalThreadsQuery(userId, teamId string, opts model.
})
if teamId != "" {
query = query.
Where(sq.Or{
sq.Eq{"Threads.ThreadTeamId": teamId},
sq.Eq{"Threads.ThreadTeamId": ""},
})
if opts.ExcludeDirect {
query = query.Where(sq.Eq{"Threads.ThreadTeamId": teamId})
} else {
query = query.Where(
sq.Or{
sq.Eq{"Threads.ThreadTeamId": teamId},
sq.Eq{"Threads.ThreadTeamId": ""},
},
)
}
}
if !opts.Deleted {
@ -196,11 +201,16 @@ func (s *SqlThreadStore) GetTotalUnreadMentions(userId, teamId string, opts mode
})
if teamId != "" {
query = query.
Where(sq.Or{
sq.Eq{"Threads.ThreadTeamId": teamId},
sq.Eq{"Threads.ThreadTeamId": ""},
})
if opts.ExcludeDirect {
query = query.Where(sq.Eq{"Threads.ThreadTeamId": teamId})
} else {
query = query.Where(
sq.Or{
sq.Eq{"Threads.ThreadTeamId": teamId},
sq.Eq{"Threads.ThreadTeamId": ""},
},
)
}
}
if !opts.Deleted {
@ -235,11 +245,16 @@ func (s *SqlThreadStore) GetTotalUnreadUrgentMentions(userId, teamId string, opt
}
if teamId != "" {
query = query.
Where(sq.Or{
sq.Eq{"Threads.ThreadTeamId": teamId},
sq.Eq{"Threads.ThreadTeamId": ""},
})
if opts.ExcludeDirect {
query = query.Where(sq.Eq{"Threads.ThreadTeamId": teamId})
} else {
query = query.Where(
sq.Or{
sq.Eq{"Threads.ThreadTeamId": teamId},
sq.Eq{"Threads.ThreadTeamId": ""},
},
)
}
}
if !opts.Deleted {
@ -296,14 +311,19 @@ func (s *SqlThreadStore) GetThreadsForUser(userId, teamId string, opts model.Get
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.
if teamId != "" {
query = query.
Where(sq.Or{
sq.Eq{"Threads.ThreadTeamId": teamId},
sq.Eq{"Threads.ThreadTeamId": ""},
})
if opts.ExcludeDirect {
query = query.Where(sq.Eq{"Threads.ThreadTeamId": teamId})
} else {
query = query.Where(
sq.Or{
sq.Eq{"Threads.ThreadTeamId": teamId},
sq.Eq{"Threads.ThreadTeamId": ""},
},
)
}
}
if !opts.Deleted {

View file

@ -916,6 +916,13 @@ func testVarious(t *testing.T, rctx request.CTX, ss store.Store) {
ChannelId: gm1.Id,
UserId: user1ID,
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)
@ -1077,6 +1084,9 @@ func testVarious(t *testing.T, rctx request.CTX, ss store.Store) {
{"team2, user1", user1ID, team2.Id, model.GetUserThreadsOpts{}, []*model.Post{
gm1post1,
}},
{"team1, user1, exclude direct", user1ID, team1.Id, model.GetUserThreadsOpts{ExcludeDirect: true}, []*model.Post{
team1channel1post3,
}},
}
for _, testCase := range testCases {
@ -1098,12 +1108,13 @@ func testVarious(t *testing.T, rctx request.CTX, ss store.Store) {
ExpectedThreads []*model.Post
}{
{"all teams, user1", user1ID, "", model.GetUserThreadsOpts{}, []*model.Post{
team1channel1post3,
team1channel1post3, gm1post1,
}},
{"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 {
@ -1183,6 +1194,9 @@ func testVarious(t *testing.T, rctx request.CTX, ss store.Store) {
{"team2, user1", user1ID, team2.Id, model.GetUserThreadsOpts{}, []*model.Post{
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{
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{
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 {

View file

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

View file

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