From bb7e5b6e9dced3f9e0b9c3a3f89161c5ec266f62 Mon Sep 17 00:00:00 2001 From: Eli Yukelzon Date: Sun, 31 Jan 2021 11:54:35 +0200 Subject: [PATCH] MM-31712 Server/API: Unreads-only filter for GetUserThreads (#16660) Co-authored-by: Mattermod --- api4/user.go | 3 +++ api4/user_test.go | 18 ++++++++++++++++-- model/client4.go | 4 +++- model/thread.go | 3 +++ store/sqlstore/thread_store.go | 13 +++++++++++-- 5 files changed, 36 insertions(+), 5 deletions(-) diff --git a/api4/user.go b/api4/user.go index bd652b8590..dcd07f6a6d 100644 --- a/api4/user.go +++ b/api4/user.go @@ -2857,6 +2857,7 @@ func getThreadsForUser(c *Context, w http.ResponseWriter, r *http.Request) { Since: 0, Page: 0, PageSize: 30, + Unread: false, Extended: false, Deleted: false, } @@ -2892,9 +2893,11 @@ func getThreadsForUser(c *Context, w http.ResponseWriter, r *http.Request) { } deletedStr := r.URL.Query().Get("deleted") + unreadStr := r.URL.Query().Get("unread") extendedStr := r.URL.Query().Get("extended") options.Deleted, _ = strconv.ParseBool(deletedStr) + options.Unread, _ = strconv.ParseBool(unreadStr) options.Extended, _ = strconv.ParseBool(extendedStr) threads, err := c.App.GetThreadsForUser(c.Params.UserId, c.Params.TeamId, options) diff --git a/api4/user_test.go b/api4/user_test.go index 2a10523157..d41978224e 100644 --- a/api4/user_test.go +++ b/api4/user_test.go @@ -5618,8 +5618,22 @@ func TestMaintainUnreadRepliesInThread(t *testing.T) { // reply count should be 0 checkThreadListReplies(t, th, th.Client, th.BasicUser.Id, 0, 1, nil) - // the other user should also have 2 - checkThreadListReplies(t, th, th.SystemAdminClient, th.SystemAdminUser.Id, 2, 1, nil) + // mark other user's read state + resp = th.SystemAdminClient.UpdateThreadReadForUser(th.SystemAdminUser.Id, th.BasicTeam.Id, rpost.Id, model.GetMillis()) + CheckNoError(t, resp) + CheckOKStatus(t, resp) + + // get unread only, should return nothing + checkThreadListReplies(t, th, th.SystemAdminClient, th.SystemAdminUser.Id, 0, 0, &model.GetUserThreadsOpts{Unread: true}) + + // restore unread to an old date + resp = th.SystemAdminClient.UpdateThreadReadForUser(th.SystemAdminUser.Id, th.BasicTeam.Id, rpost.Id, 123) + CheckNoError(t, resp) + CheckOKStatus(t, resp) + + // should have 2 unread replies now + checkThreadListReplies(t, th, th.SystemAdminClient, th.SystemAdminUser.Id, 2, 1, &model.GetUserThreadsOpts{Unread: true}) + } func TestThreadCounts(t *testing.T) { diff --git a/model/client4.go b/model/client4.go index 89c60115b5..70e90f980a 100644 --- a/model/client4.go +++ b/model/client4.go @@ -5806,7 +5806,9 @@ func (c *Client4) GetUserThreads(userId, teamId string, options GetUserThreadsOp if options.Deleted { v.Set("deleted", "true") } - + if options.Unread { + v.Set("unread", "true") + } url := c.GetUserThreadsRoute(userId, teamId) if len(v) > 0 { url += "?" + v.Encode() diff --git a/model/thread.go b/model/thread.go index a1a94842c1..aaef61d1ac 100644 --- a/model/thread.go +++ b/model/thread.go @@ -48,6 +48,9 @@ type GetUserThreadsOpts struct { // Since filters the threads based on their LastUpdateAt timestamp. Since uint64 + + // Unread will make sure that only threads with unread replies are returned + Unread bool } func (o *ThreadResponse) ToJson() string { diff --git a/store/sqlstore/thread_store.go b/store/sqlstore/thread_store.go index 7349cdd1b6..e34c5bebda 100644 --- a/store/sqlstore/thread_store.go +++ b/store/sqlstore/thread_store.go @@ -153,13 +153,19 @@ func (s *SqlThreadStore) GetThreadsForUser(userId, teamId string, opts model.Get close(totalUnreadThreadsChan) }() go func() { + newFetchConditions := fetchConditions + + if opts.Unread { + newFetchConditions = sq.And{newFetchConditions, sq.Expr("ThreadMemberships.LastViewed < Threads.LastReplyAt")} + } + threadsQuery, threadsQueryArgs, _ := s.getQueryBuilder(). Select("COUNT(ThreadMemberships.PostId)"). LeftJoin("Threads ON Threads.PostId = ThreadMemberships.PostId"). LeftJoin("Channels ON Threads.ChannelId = Channels.Id"). LeftJoin("Posts ON Posts.Id = ThreadMemberships.PostId"). From("ThreadMemberships"). - Where(fetchConditions).ToSql() + Where(newFetchConditions).ToSql() totalCount, err := s.GetMaster().SelectInt(threadsQuery, threadsQueryArgs...) totalCountChan <- store.StoreResult{Data: totalCount, NErr: err} @@ -180,7 +186,10 @@ func (s *SqlThreadStore) GetThreadsForUser(userId, teamId string, opts model.Get go func() { newFetchConditions := fetchConditions if opts.Since > 0 { - newFetchConditions = sq.And{newFetchConditions, sq.GtOrEq{"Threads.LastReplyAt": opts.Since}} + newFetchConditions = sq.And{newFetchConditions, sq.GtOrEq{"ThreadMemberships.LastUpdated": opts.Since}} + } + if opts.Unread { + newFetchConditions = sq.And{newFetchConditions, sq.Expr("ThreadMemberships.LastViewed < Threads.LastReplyAt")} } var threads []*JoinedThread