MM-40148: threadsOnly query param for user threads (#19833)
* MM-40148: threadsOnly query param for user threads Currently we always calculate counts when fetching user threads. Those counts include total, unread replies, and unread mentions, and are potentially expensive to calculate. This commit adds a new query param 'threadsOnly' which won't calculate any counts and just return threads. Co-authored-by: koox00 <3829551+koox00@users.noreply.github.com> Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
27bd16e5f5
Коммит
9521797b15
30
api4/user.go
30
api4/user.go
@@ -3008,14 +3008,15 @@ func getThreadsForUser(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
options := model.GetUserThreadsOpts{
|
||||
Since: 0,
|
||||
Before: "",
|
||||
After: "",
|
||||
PageSize: uint64(c.Params.PerPage),
|
||||
Unread: false,
|
||||
Extended: false,
|
||||
Deleted: false,
|
||||
TotalsOnly: false,
|
||||
Since: 0,
|
||||
Before: "",
|
||||
After: "",
|
||||
PageSize: uint64(c.Params.PerPage),
|
||||
Unread: false,
|
||||
Extended: false,
|
||||
Deleted: false,
|
||||
TotalsOnly: false,
|
||||
ThreadsOnly: false,
|
||||
}
|
||||
|
||||
sinceString := r.URL.Query().Get("since")
|
||||
@@ -3030,21 +3031,30 @@ func getThreadsForUser(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
options.Before = r.URL.Query().Get("before")
|
||||
options.After = r.URL.Query().Get("after")
|
||||
totalsOnlyStr := r.URL.Query().Get("totalsOnly")
|
||||
threadsOnlyStr := r.URL.Query().Get("threadsOnly")
|
||||
options.TotalsOnly, _ = strconv.ParseBool(totalsOnlyStr)
|
||||
options.ThreadsOnly, _ = strconv.ParseBool(threadsOnlyStr)
|
||||
|
||||
// parameters are mutually exclusive
|
||||
if options.Before != "" && options.After != "" {
|
||||
c.Err = model.NewAppError("api.getThreadsForUser", "api.getThreadsForUser.bad_params", nil, "", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// parameters are mutually exclusive
|
||||
if options.TotalsOnly && options.ThreadsOnly {
|
||||
c.Err = model.NewAppError("api.getThreadsForUser", "api.getThreadsForUser.bad_only_params", nil, "", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
deletedStr := r.URL.Query().Get("deleted")
|
||||
unreadStr := r.URL.Query().Get("unread")
|
||||
extendedStr := r.URL.Query().Get("extended")
|
||||
totalsOnlyStr := r.URL.Query().Get("totalsOnly")
|
||||
|
||||
options.Deleted, _ = strconv.ParseBool(deletedStr)
|
||||
options.Unread, _ = strconv.ParseBool(unreadStr)
|
||||
options.Extended, _ = strconv.ParseBool(extendedStr)
|
||||
options.TotalsOnly, _ = strconv.ParseBool(totalsOnlyStr)
|
||||
|
||||
threads, err := c.App.GetThreadsForUser(c.Params.UserId, c.Params.TeamId, options)
|
||||
if err != nil {
|
||||
|
||||
@@ -5754,6 +5754,96 @@ func TestGetThreadsForUser(t *testing.T) {
|
||||
require.Len(t, uss3.Threads, 0)
|
||||
})
|
||||
|
||||
t.Run("totalsOnly param", func(t *testing.T) {
|
||||
client := th.Client
|
||||
sysadminClient := th.SystemAdminClient
|
||||
|
||||
var rootIds []*model.Post
|
||||
for i := 0; i < 10; i++ {
|
||||
rpost, resp, err := client.CreatePost(&model.Post{ChannelId: th.BasicChannel.Id, Message: "testMsg"})
|
||||
require.NoError(t, err)
|
||||
CheckCreatedStatus(t, resp)
|
||||
rootIds = append(rootIds, rpost)
|
||||
if i%2 == 0 {
|
||||
_, resp, err = client.CreatePost(&model.Post{ChannelId: th.BasicChannel.Id, Message: "testReply", RootId: rpost.Id})
|
||||
} else {
|
||||
_, resp, err = sysadminClient.CreatePost(&model.Post{ChannelId: th.BasicChannel.Id, Message: "testReply @" + th.BasicUser.Username, RootId: rpost.Id})
|
||||
}
|
||||
require.NoError(t, err)
|
||||
CheckCreatedStatus(t, resp)
|
||||
}
|
||||
|
||||
defer th.App.Srv().Store.Post().PermanentDeleteByUser(th.BasicUser.Id)
|
||||
defer th.App.Srv().Store.Post().PermanentDeleteByUser(th.SystemAdminUser.Id)
|
||||
|
||||
uss, _, err := th.Client.GetUserThreads(th.BasicUser.Id, th.BasicTeam.Id, model.GetUserThreadsOpts{
|
||||
Deleted: false,
|
||||
TotalsOnly: true,
|
||||
PageSize: 30,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Len(t, uss.Threads, 0)
|
||||
require.Len(t, rootIds, 10)
|
||||
require.Equal(t, int64(10), uss.Total)
|
||||
require.Equal(t, int64(5), uss.TotalUnreadThreads)
|
||||
require.Equal(t, int64(5), uss.TotalUnreadMentions)
|
||||
})
|
||||
|
||||
t.Run("threadsOnly param", func(t *testing.T) {
|
||||
client := th.Client
|
||||
sysadminClient := th.SystemAdminClient
|
||||
|
||||
var rootIds []*model.Post
|
||||
for i := 0; i < 10; i++ {
|
||||
rpost, resp, err := client.CreatePost(&model.Post{ChannelId: th.BasicChannel.Id, Message: "testMsg"})
|
||||
require.NoError(t, err)
|
||||
CheckCreatedStatus(t, resp)
|
||||
rootIds = append(rootIds, rpost)
|
||||
if i%2 == 0 {
|
||||
_, resp, err = client.CreatePost(&model.Post{ChannelId: th.BasicChannel.Id, Message: "testReply", RootId: rpost.Id})
|
||||
} else {
|
||||
_, resp, err = sysadminClient.CreatePost(&model.Post{ChannelId: th.BasicChannel.Id, Message: "testReply @" + th.BasicUser.Username, RootId: rpost.Id})
|
||||
}
|
||||
|
||||
require.NoError(t, err)
|
||||
CheckCreatedStatus(t, resp)
|
||||
}
|
||||
|
||||
defer th.App.Srv().Store.Post().PermanentDeleteByUser(th.BasicUser.Id)
|
||||
defer th.App.Srv().Store.Post().PermanentDeleteByUser(th.SystemAdminUser.Id)
|
||||
|
||||
uss, _, err := th.Client.GetUserThreads(th.BasicUser.Id, th.BasicTeam.Id, model.GetUserThreadsOpts{
|
||||
Deleted: false,
|
||||
ThreadsOnly: true,
|
||||
PageSize: 30,
|
||||
})
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Len(t, rootIds, 10)
|
||||
require.Len(t, uss.Threads, 10)
|
||||
require.Equal(t, int64(0), uss.Total)
|
||||
require.Equal(t, int64(0), uss.TotalUnreadThreads)
|
||||
require.Equal(t, int64(0), uss.TotalUnreadMentions)
|
||||
require.Equal(t, int64(1), uss.Threads[0].ReplyCount)
|
||||
|
||||
require.Equal(t, rootIds[9].Id, uss.Threads[0].PostId)
|
||||
require.Equal(t, th.SystemAdminUser.Id, uss.Threads[0].Participants[0].Id)
|
||||
require.Equal(t, th.BasicUser.Id, uss.Threads[1].Participants[0].Id)
|
||||
})
|
||||
|
||||
t.Run("setting both threadsOnly, and totalsOnly params is not allowed", func(t *testing.T) {
|
||||
defer th.App.Srv().Store.Post().PermanentDeleteByUser(th.BasicUser.Id)
|
||||
|
||||
_, resp, err := th.Client.GetUserThreads(th.BasicUser.Id, th.BasicTeam.Id, model.GetUserThreadsOpts{
|
||||
ThreadsOnly: true,
|
||||
TotalsOnly: true,
|
||||
PageSize: 30,
|
||||
})
|
||||
|
||||
require.Error(t, err)
|
||||
checkHTTPStatus(t, resp, http.StatusBadRequest)
|
||||
})
|
||||
|
||||
t.Run("editing or reacting to reply post does not make thread unread", func(t *testing.T) {
|
||||
client := th.Client
|
||||
|
||||
|
||||
Ссылка в новой задаче
Block a user