[MM-42191]: Include deleted posts (#19985)

* MM-42191: Include deleted posts: Add includeDeleted query parameter for getPostsForChannel

* MM-42191: Fix error typo for includeDeleted query parameter

* MM-42191: Include deleted posts: Set permission error when deleted posts are requested by non system admins

* MM-42191: Include deleted posts: Refactor replyCountSubQuery and conditions when includeDeleted is not presented, refactor getRootPosts

* MM-42191: Include deleted posts: Refactor getRootPosts function along with skipFetchThreads and includeDeleted

* MM-42191: Include deleted posts: Rename includeDeleted to include_deleted param

* MM-42191: Include deleted posts: Fix failed posts unit tests

* MM-42191: Include deleted posts: Add missing include deleted option in multiple queries

* MM-42191: Include deleted posts: Add tests for include deleted option in TestGetPostsForChannel, TestGetPostsBefore, TestGetPostsAfter

* MM-42191: include deleted posts: Add tests cases for post store test

* MM-42191: Include deleted posts: Add extra unit test to ensure not returning deleted posts when IncludeDelete is false

Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
Этот коммит содержится в:
Orlando Romo
2022-09-27 13:00:42 -05:00
коммит произвёл GitHub
родитель 1d8bb0605c
Коммит b9834a2fc2
9 изменённых файлов: 269 добавлений и 77 удалений

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

@@ -33,7 +33,7 @@ func TestEchoCommand(t *testing.T) {
time.Sleep(100 * time.Millisecond) time.Sleep(100 * time.Millisecond)
p1, _, err := client.GetPostsForChannel(channel1.Id, 0, 2, "", false) p1, _, err := client.GetPostsForChannel(channel1.Id, 0, 2, "", false, false)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, p1.Order, 2, "Echo command failed to send") require.Len(t, p1.Order, 2, "Echo command failed to send")
} }
@@ -352,7 +352,7 @@ func TestMeCommand(t *testing.T) {
time.Sleep(100 * time.Millisecond) time.Sleep(100 * time.Millisecond)
p1, _, err := client.GetPostsForChannel(channel.Id, 0, 2, "", false) p1, _, err := client.GetPostsForChannel(channel.Id, 0, 2, "", false, false)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, p1.Order, 2, "Command failed to send") require.Len(t, p1.Order, 2, "Command failed to send")
@@ -454,7 +454,7 @@ func TestShrugCommand(t *testing.T) {
time.Sleep(100 * time.Millisecond) time.Sleep(100 * time.Millisecond)
p1, _, err := client.GetPostsForChannel(channel.Id, 0, 2, "", false) p1, _, err := client.GetPostsForChannel(channel.Id, 0, 2, "", false, false)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, p1.Order, 2, "Command failed to send") require.Len(t, p1.Order, 2, "Command failed to send")
require.Equal(t, `¯\\\_(ツ)\_/¯`, p1.Posts[p1.Order[0]].Message, "invalid shrug response") require.Equal(t, `¯\\\_(ツ)\_/¯`, p1.Posts[p1.Order[0]].Message, "invalid shrug response")

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

@@ -183,10 +183,16 @@ func getPostsForChannel(c *Context, w http.ResponseWriter, r *http.Request) {
skipFetchThreads := r.URL.Query().Get("skipFetchThreads") == "true" skipFetchThreads := r.URL.Query().Get("skipFetchThreads") == "true"
collapsedThreads := r.URL.Query().Get("collapsedThreads") == "true" collapsedThreads := r.URL.Query().Get("collapsedThreads") == "true"
collapsedThreadsExtended := r.URL.Query().Get("collapsedThreadsExtended") == "true" collapsedThreadsExtended := r.URL.Query().Get("collapsedThreadsExtended") == "true"
includeDeleted := r.URL.Query().Get("include_deleted") == "true"
channelId := c.Params.ChannelId channelId := c.Params.ChannelId
page := c.Params.Page page := c.Params.Page
perPage := c.Params.PerPage perPage := c.Params.PerPage
if !c.IsSystemAdmin() && includeDeleted {
c.SetPermissionError(model.PermissionReadDeletedPosts)
return
}
if !c.App.SessionHasPermissionToChannel(c.AppContext, *c.AppContext.Session(), channelId, model.PermissionReadChannel) { if !c.App.SessionHasPermissionToChannel(c.AppContext, *c.AppContext.Session(), channelId, model.PermissionReadChannel) {
c.SetPermissionError(model.PermissionReadChannel) c.SetPermissionError(model.PermissionReadChannel)
return return
@@ -217,7 +223,7 @@ func getPostsForChannel(c *Context, w http.ResponseWriter, r *http.Request) {
return return
} }
list, err = c.App.GetPostsAfterPost(model.GetPostsOptions{ChannelId: channelId, PostId: afterPost, Page: page, PerPage: perPage, SkipFetchThreads: skipFetchThreads, CollapsedThreads: collapsedThreads, UserId: c.AppContext.Session().UserId}) list, err = c.App.GetPostsAfterPost(model.GetPostsOptions{ChannelId: channelId, PostId: afterPost, Page: page, PerPage: perPage, SkipFetchThreads: skipFetchThreads, CollapsedThreads: collapsedThreads, UserId: c.AppContext.Session().UserId, IncludeDeleted: includeDeleted})
} else if beforePost != "" { } else if beforePost != "" {
etag = c.App.GetPostsEtag(channelId, collapsedThreads) etag = c.App.GetPostsEtag(channelId, collapsedThreads)
@@ -225,7 +231,7 @@ func getPostsForChannel(c *Context, w http.ResponseWriter, r *http.Request) {
return return
} }
list, err = c.App.GetPostsBeforePost(model.GetPostsOptions{ChannelId: channelId, PostId: beforePost, Page: page, PerPage: perPage, SkipFetchThreads: skipFetchThreads, CollapsedThreads: collapsedThreads, CollapsedThreadsExtended: collapsedThreadsExtended, UserId: c.AppContext.Session().UserId}) list, err = c.App.GetPostsBeforePost(model.GetPostsOptions{ChannelId: channelId, PostId: beforePost, Page: page, PerPage: perPage, SkipFetchThreads: skipFetchThreads, CollapsedThreads: collapsedThreads, CollapsedThreadsExtended: collapsedThreadsExtended, UserId: c.AppContext.Session().UserId, IncludeDeleted: includeDeleted})
} else { } else {
etag = c.App.GetPostsEtag(channelId, collapsedThreads) etag = c.App.GetPostsEtag(channelId, collapsedThreads)
@@ -233,7 +239,7 @@ func getPostsForChannel(c *Context, w http.ResponseWriter, r *http.Request) {
return return
} }
list, err = c.App.GetPostsPage(model.GetPostsOptions{ChannelId: channelId, Page: page, PerPage: perPage, SkipFetchThreads: skipFetchThreads, CollapsedThreads: collapsedThreads, CollapsedThreadsExtended: collapsedThreadsExtended, UserId: c.AppContext.Session().UserId}) list, err = c.App.GetPostsPage(model.GetPostsOptions{ChannelId: channelId, Page: page, PerPage: perPage, SkipFetchThreads: skipFetchThreads, CollapsedThreads: collapsedThreads, CollapsedThreadsExtended: collapsedThreadsExtended, UserId: c.AppContext.Session().UserId, IncludeDeleted: includeDeleted})
} }
if err != nil { if err != nil {

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

@@ -1068,17 +1068,17 @@ func TestGetPostsForChannel(t *testing.T) {
post4 := th.CreatePost() post4 := th.CreatePost()
th.TestForAllClients(t, func(t *testing.T, c *model.Client4) { th.TestForAllClients(t, func(t *testing.T, c *model.Client4) {
posts, resp, err := c.GetPostsForChannel(th.BasicChannel.Id, 0, 60, "", false) posts, resp, err := c.GetPostsForChannel(th.BasicChannel.Id, 0, 60, "", false, false)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, post4.Id, posts.Order[0], "wrong order") require.Equal(t, post4.Id, posts.Order[0], "wrong order")
require.Equal(t, post3.Id, posts.Order[1], "wrong order") require.Equal(t, post3.Id, posts.Order[1], "wrong order")
require.Equal(t, post2.Id, posts.Order[2], "wrong order") require.Equal(t, post2.Id, posts.Order[2], "wrong order")
require.Equal(t, post1.Id, posts.Order[3], "wrong order") require.Equal(t, post1.Id, posts.Order[3], "wrong order")
posts, resp, _ = c.GetPostsForChannel(th.BasicChannel.Id, 0, 3, resp.Etag, false) posts, resp, _ = c.GetPostsForChannel(th.BasicChannel.Id, 0, 3, resp.Etag, false, false)
CheckEtag(t, posts, resp) CheckEtag(t, posts, resp)
posts, _, err = c.GetPostsForChannel(th.BasicChannel.Id, 0, 3, "", false) posts, _, err = c.GetPostsForChannel(th.BasicChannel.Id, 0, 3, "", false, false)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, posts.Order, 3, "wrong number returned") require.Len(t, posts.Order, 3, "wrong number returned")
@@ -1087,11 +1087,11 @@ func TestGetPostsForChannel(t *testing.T) {
_, ok = posts.Posts[post1.Id] _, ok = posts.Posts[post1.Id]
require.True(t, ok, "missing root post") require.True(t, ok, "missing root post")
posts, _, err = c.GetPostsForChannel(th.BasicChannel.Id, 1, 1, "", false) posts, _, err = c.GetPostsForChannel(th.BasicChannel.Id, 1, 1, "", false, false)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, post3.Id, posts.Order[0], "wrong order") require.Equal(t, post3.Id, posts.Order[0], "wrong order")
posts, _, err = c.GetPostsForChannel(th.BasicChannel.Id, 10000, 10000, "", false) posts, _, err = c.GetPostsForChannel(th.BasicChannel.Id, 10000, 10000, "", false, false)
require.NoError(t, err) require.NoError(t, err)
require.Empty(t, posts.Order, "should be no posts") require.Empty(t, posts.Order, "should be no posts")
}) })
@@ -1121,21 +1121,21 @@ func TestGetPostsForChannel(t *testing.T) {
require.True(t, f, "missing post") require.True(t, f, "missing post")
} }
_, resp, err := c.GetPostsForChannel("", 0, 60, "", false) _, resp, err := c.GetPostsForChannel("", 0, 60, "", false, false)
require.Error(t, err) require.Error(t, err)
CheckBadRequestStatus(t, resp) CheckBadRequestStatus(t, resp)
_, resp, err = c.GetPostsForChannel("junk", 0, 60, "", false) _, resp, err = c.GetPostsForChannel("junk", 0, 60, "", false, false)
require.Error(t, err) require.Error(t, err)
CheckBadRequestStatus(t, resp) CheckBadRequestStatus(t, resp)
}) })
_, resp, err := client.GetPostsForChannel(model.NewId(), 0, 60, "", false) _, resp, err := client.GetPostsForChannel(model.NewId(), 0, 60, "", false, false)
require.Error(t, err) require.Error(t, err)
CheckForbiddenStatus(t, resp) CheckForbiddenStatus(t, resp)
client.Logout() client.Logout()
_, resp, err = client.GetPostsForChannel(model.NewId(), 0, 60, "", false) _, resp, err = client.GetPostsForChannel(model.NewId(), 0, 60, "", false, false)
require.Error(t, err) require.Error(t, err)
CheckUnauthorizedStatus(t, resp) CheckUnauthorizedStatus(t, resp)
@@ -1151,12 +1151,12 @@ func TestGetPostsForChannel(t *testing.T) {
var posts *model.PostList var posts *model.PostList
th.TestForAllClients(t, func(t *testing.T, c *model.Client4) { th.TestForAllClients(t, func(t *testing.T, c *model.Client4) {
// get the system post IDs posted before the created posts above // get the system post IDs posted before the created posts above
posts, _, err = c.GetPostsBefore(th.BasicChannel.Id, post1.Id, 0, 2, "", false) posts, _, err = c.GetPostsBefore(th.BasicChannel.Id, post1.Id, 0, 2, "", false, false)
require.NoError(t, err) require.NoError(t, err)
systemPostId1 := posts.Order[1] systemPostId1 := posts.Order[1]
// similar to '/posts' // similar to '/posts'
posts, _, err = c.GetPostsForChannel(th.BasicChannel.Id, 0, 60, "", false) posts, _, err = c.GetPostsForChannel(th.BasicChannel.Id, 0, 60, "", false, false)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, posts.Order, 12, "expected 12 posts") require.Len(t, posts.Order, 12, "expected 12 posts")
require.Equal(t, post10.Id, posts.Order[0], "posts not in order") require.Equal(t, post10.Id, posts.Order[0], "posts not in order")
@@ -1165,7 +1165,7 @@ func TestGetPostsForChannel(t *testing.T) {
require.Equal(t, "", posts.PrevPostId, "should return an empty PrevPostId") require.Equal(t, "", posts.PrevPostId, "should return an empty PrevPostId")
// similar to '/posts?per_page=3' // similar to '/posts?per_page=3'
posts, _, err = c.GetPostsForChannel(th.BasicChannel.Id, 0, 3, "", false) posts, _, err = c.GetPostsForChannel(th.BasicChannel.Id, 0, 3, "", false, false)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, posts.Order, 3, "expected 3 posts") require.Len(t, posts.Order, 3, "expected 3 posts")
require.Equal(t, post10.Id, posts.Order[0], "posts not in order") require.Equal(t, post10.Id, posts.Order[0], "posts not in order")
@@ -1174,7 +1174,7 @@ func TestGetPostsForChannel(t *testing.T) {
require.Equal(t, post7.Id, posts.PrevPostId, "should return post7.Id as PrevPostId") require.Equal(t, post7.Id, posts.PrevPostId, "should return post7.Id as PrevPostId")
// similar to '/posts?per_page=3&page=1' // similar to '/posts?per_page=3&page=1'
posts, _, err = c.GetPostsForChannel(th.BasicChannel.Id, 1, 3, "", false) posts, _, err = c.GetPostsForChannel(th.BasicChannel.Id, 1, 3, "", false, false)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, posts.Order, 3, "expected 3 posts") require.Len(t, posts.Order, 3, "expected 3 posts")
require.Equal(t, post7.Id, posts.Order[0], "posts not in order") require.Equal(t, post7.Id, posts.Order[0], "posts not in order")
@@ -1183,7 +1183,7 @@ func TestGetPostsForChannel(t *testing.T) {
require.Equal(t, post4.Id, posts.PrevPostId, "should return post4.Id as PrevPostId") require.Equal(t, post4.Id, posts.PrevPostId, "should return post4.Id as PrevPostId")
// similar to '/posts?per_page=3&page=2' // similar to '/posts?per_page=3&page=2'
posts, _, err = c.GetPostsForChannel(th.BasicChannel.Id, 2, 3, "", false) posts, _, err = c.GetPostsForChannel(th.BasicChannel.Id, 2, 3, "", false, false)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, posts.Order, 3, "expected 3 posts") require.Len(t, posts.Order, 3, "expected 3 posts")
require.Equal(t, post4.Id, posts.Order[0], "posts not in order") require.Equal(t, post4.Id, posts.Order[0], "posts not in order")
@@ -1192,7 +1192,7 @@ func TestGetPostsForChannel(t *testing.T) {
require.Equal(t, post1.Id, posts.PrevPostId, "should return post1.Id as PrevPostId") require.Equal(t, post1.Id, posts.PrevPostId, "should return post1.Id as PrevPostId")
// similar to '/posts?per_page=3&page=3' // similar to '/posts?per_page=3&page=3'
posts, _, err = c.GetPostsForChannel(th.BasicChannel.Id, 3, 3, "", false) posts, _, err = c.GetPostsForChannel(th.BasicChannel.Id, 3, 3, "", false, false)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, posts.Order, 3, "expected 3 posts") require.Len(t, posts.Order, 3, "expected 3 posts")
require.Equal(t, post1.Id, posts.Order[0], "posts not in order") require.Equal(t, post1.Id, posts.Order[0], "posts not in order")
@@ -1201,7 +1201,7 @@ func TestGetPostsForChannel(t *testing.T) {
require.Equal(t, "", posts.PrevPostId, "should return an empty PrevPostId") require.Equal(t, "", posts.PrevPostId, "should return an empty PrevPostId")
// similar to '/posts?per_page=3&page=4' // similar to '/posts?per_page=3&page=4'
posts, _, err = c.GetPostsForChannel(th.BasicChannel.Id, 4, 3, "", false) posts, _, err = c.GetPostsForChannel(th.BasicChannel.Id, 4, 3, "", false, false)
require.NoError(t, err) require.NoError(t, err)
require.Empty(t, posts.Order, "should return 0 post") require.Empty(t, posts.Order, "should return 0 post")
require.Equal(t, "", posts.NextPostId, "should return an empty NextPostId") require.Equal(t, "", posts.NextPostId, "should return an empty NextPostId")
@@ -1220,15 +1220,37 @@ func TestGetPostsForChannel(t *testing.T) {
}) })
// the endpoint should work fine when viewing archived channels is enabled // the endpoint should work fine when viewing archived channels is enabled
_, _, err = c.GetPostsForChannel(channel.Id, 0, 10, "", false) _, _, err = c.GetPostsForChannel(channel.Id, 0, 10, "", false, false)
require.NoError(t, err) require.NoError(t, err)
// the endpoint should return forbidden if viewing archived channels is disabled // the endpoint should return forbidden if viewing archived channels is disabled
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.ExperimentalViewArchivedChannels = false }) th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.ExperimentalViewArchivedChannels = false })
_, resp, err = c.GetPostsForChannel(channel.Id, 0, 10, "", false) _, resp, err = c.GetPostsForChannel(channel.Id, 0, 10, "", false, false)
require.Error(t, err) require.Error(t, err)
CheckForbiddenStatus(t, resp) CheckForbiddenStatus(t, resp)
}, "Should forbid to retrieve posts if the channel is archived and users are not allowed to view archived messages") }, "Should forbid to retrieve posts if the channel is archived and users are not allowed to view archived messages")
client.DeletePost(post10.Id)
client.DeletePost(post8.Id)
// include deleted posts for non-admin users.
_, resp, err = client.GetPostsForChannel(th.BasicChannel.Id, 0, 100, "", false, true)
require.Error(t, err)
CheckForbiddenStatus(t, resp)
th.TestForSystemAdminAndLocal(t, func(t *testing.T, c *model.Client4) {
// include deleted posts for admin users.
posts, resp, err = c.GetPostsForChannel(th.BasicChannel.Id, 0, 100, "", false, true)
require.NoError(t, err)
CheckOKStatus(t, resp)
require.Len(t, posts.Order, 12, "expected 12 posts")
// not include deleted posts for admin users.
posts, resp, err = c.GetPostsForChannel(th.BasicChannel.Id, 0, 100, "", false, false)
require.NoError(t, err)
CheckOKStatus(t, resp)
require.Len(t, posts.Order, 10, "expected 10 posts")
})
} }
func TestGetFlaggedPostsForUser(t *testing.T) { func TestGetFlaggedPostsForUser(t *testing.T) {
@@ -1440,7 +1462,7 @@ func TestGetPostsBefore(t *testing.T) {
post4 := th.CreatePost() post4 := th.CreatePost()
post5 := th.CreatePost() post5 := th.CreatePost()
posts, _, err := client.GetPostsBefore(th.BasicChannel.Id, post3.Id, 0, 100, "", false) posts, _, err := client.GetPostsBefore(th.BasicChannel.Id, post3.Id, 0, 100, "", false, false)
require.NoError(t, err) require.NoError(t, err)
found := make([]bool, 2) found := make([]bool, 2)
@@ -1462,18 +1484,18 @@ func TestGetPostsBefore(t *testing.T) {
require.Equal(t, post3.Id, posts.NextPostId, "should match NextPostId") require.Equal(t, post3.Id, posts.NextPostId, "should match NextPostId")
require.Equal(t, "", posts.PrevPostId, "should match empty PrevPostId") require.Equal(t, "", posts.PrevPostId, "should match empty PrevPostId")
posts, _, err = client.GetPostsBefore(th.BasicChannel.Id, post4.Id, 1, 1, "", false) posts, _, err = client.GetPostsBefore(th.BasicChannel.Id, post4.Id, 1, 1, "", false, false)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, posts.Posts, 1, "too many posts returned") require.Len(t, posts.Posts, 1, "too many posts returned")
require.Equal(t, post2.Id, posts.Order[0], "should match returned post") require.Equal(t, post2.Id, posts.Order[0], "should match returned post")
require.Equal(t, post3.Id, posts.NextPostId, "should match NextPostId") require.Equal(t, post3.Id, posts.NextPostId, "should match NextPostId")
require.Equal(t, post1.Id, posts.PrevPostId, "should match PrevPostId") require.Equal(t, post1.Id, posts.PrevPostId, "should match PrevPostId")
_, resp, err := client.GetPostsBefore(th.BasicChannel.Id, "junk", 1, 1, "", false) _, resp, err := client.GetPostsBefore(th.BasicChannel.Id, "junk", 1, 1, "", false, false)
require.Error(t, err) require.Error(t, err)
CheckBadRequestStatus(t, resp) CheckBadRequestStatus(t, resp)
posts, _, err = client.GetPostsBefore(th.BasicChannel.Id, post5.Id, 0, 3, "", false) posts, _, err = client.GetPostsBefore(th.BasicChannel.Id, post5.Id, 0, 3, "", false, false)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, posts.Posts, 3, "should match length of posts returned") require.Len(t, posts.Posts, 3, "should match length of posts returned")
require.Equal(t, post4.Id, posts.Order[0], "should match returned post") require.Equal(t, post4.Id, posts.Order[0], "should match returned post")
@@ -1482,12 +1504,12 @@ func TestGetPostsBefore(t *testing.T) {
require.Equal(t, post1.Id, posts.PrevPostId, "should match PrevPostId") require.Equal(t, post1.Id, posts.PrevPostId, "should match PrevPostId")
// get the system post IDs posted before the created posts above // get the system post IDs posted before the created posts above
posts, _, err = client.GetPostsBefore(th.BasicChannel.Id, post1.Id, 0, 2, "", false) posts, _, err = client.GetPostsBefore(th.BasicChannel.Id, post1.Id, 0, 2, "", false, false)
require.NoError(t, err) require.NoError(t, err)
systemPostId2 := posts.Order[0] systemPostId2 := posts.Order[0]
systemPostId1 := posts.Order[1] systemPostId1 := posts.Order[1]
posts, _, err = client.GetPostsBefore(th.BasicChannel.Id, post5.Id, 1, 3, "", false) posts, _, err = client.GetPostsBefore(th.BasicChannel.Id, post5.Id, 1, 3, "", false, false)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, posts.Posts, 3, "should match length of posts returned") require.Len(t, posts.Posts, 3, "should match length of posts returned")
require.Equal(t, post1.Id, posts.Order[0], "should match returned post") require.Equal(t, post1.Id, posts.Order[0], "should match returned post")
@@ -1502,10 +1524,10 @@ func TestGetPostsBefore(t *testing.T) {
th.CreatePost() // post7 th.CreatePost() // post7
post8 := th.CreatePost() post8 := th.CreatePost()
post9 := th.CreatePost() post9 := th.CreatePost()
th.CreatePost() // post10 post10 := th.CreatePost() // post10
// similar to '/posts?before=post9' // similar to '/posts?before=post9'
posts, _, err = client.GetPostsBefore(th.BasicChannel.Id, post9.Id, 0, 60, "", false) posts, _, err = client.GetPostsBefore(th.BasicChannel.Id, post9.Id, 0, 60, "", false, false)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, posts.Order, 10, "expected 10 posts") require.Len(t, posts.Order, 10, "expected 10 posts")
require.Equal(t, post8.Id, posts.Order[0], "posts not in order") require.Equal(t, post8.Id, posts.Order[0], "posts not in order")
@@ -1514,7 +1536,7 @@ func TestGetPostsBefore(t *testing.T) {
require.Equal(t, "", posts.PrevPostId, "should return an empty PrevPostId") require.Equal(t, "", posts.PrevPostId, "should return an empty PrevPostId")
// similar to '/posts?before=post9&per_page=3' // similar to '/posts?before=post9&per_page=3'
posts, _, err = client.GetPostsBefore(th.BasicChannel.Id, post9.Id, 0, 3, "", false) posts, _, err = client.GetPostsBefore(th.BasicChannel.Id, post9.Id, 0, 3, "", false, false)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, posts.Order, 3, "expected 3 posts") require.Len(t, posts.Order, 3, "expected 3 posts")
require.Equal(t, post8.Id, posts.Order[0], "posts not in order") require.Equal(t, post8.Id, posts.Order[0], "posts not in order")
@@ -1523,7 +1545,7 @@ func TestGetPostsBefore(t *testing.T) {
require.Equal(t, post5.Id, posts.PrevPostId, "should return post5.Id as PrevPostId") require.Equal(t, post5.Id, posts.PrevPostId, "should return post5.Id as PrevPostId")
// similar to '/posts?before=post9&per_page=3&page=1' // similar to '/posts?before=post9&per_page=3&page=1'
posts, _, err = client.GetPostsBefore(th.BasicChannel.Id, post9.Id, 1, 3, "", false) posts, _, err = client.GetPostsBefore(th.BasicChannel.Id, post9.Id, 1, 3, "", false, false)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, posts.Order, 3, "expected 3 posts") require.Len(t, posts.Order, 3, "expected 3 posts")
require.Equal(t, post5.Id, posts.Order[0], "posts not in order") require.Equal(t, post5.Id, posts.Order[0], "posts not in order")
@@ -1532,7 +1554,7 @@ func TestGetPostsBefore(t *testing.T) {
require.Equal(t, post2.Id, posts.PrevPostId, "should return post2.Id as PrevPostId") require.Equal(t, post2.Id, posts.PrevPostId, "should return post2.Id as PrevPostId")
// similar to '/posts?before=post9&per_page=3&page=2' // similar to '/posts?before=post9&per_page=3&page=2'
posts, _, err = client.GetPostsBefore(th.BasicChannel.Id, post9.Id, 2, 3, "", false) posts, _, err = client.GetPostsBefore(th.BasicChannel.Id, post9.Id, 2, 3, "", false, false)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, posts.Order, 3, "expected 3 posts") require.Len(t, posts.Order, 3, "expected 3 posts")
require.Equal(t, post2.Id, posts.Order[0], "posts not in order") require.Equal(t, post2.Id, posts.Order[0], "posts not in order")
@@ -1541,7 +1563,7 @@ func TestGetPostsBefore(t *testing.T) {
require.Equal(t, systemPostId1, posts.PrevPostId, "should return systemPostId1 as PrevPostId") require.Equal(t, systemPostId1, posts.PrevPostId, "should return systemPostId1 as PrevPostId")
// similar to '/posts?before=post1&per_page=3' // similar to '/posts?before=post1&per_page=3'
posts, _, err = client.GetPostsBefore(th.BasicChannel.Id, post1.Id, 0, 3, "", false) posts, _, err = client.GetPostsBefore(th.BasicChannel.Id, post1.Id, 0, 3, "", false, false)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, posts.Order, 2, "expected 2 posts") require.Len(t, posts.Order, 2, "expected 2 posts")
require.Equal(t, systemPostId2, posts.Order[0], "posts not in order") require.Equal(t, systemPostId2, posts.Order[0], "posts not in order")
@@ -1550,14 +1572,14 @@ func TestGetPostsBefore(t *testing.T) {
require.Equal(t, "", posts.PrevPostId, "should return an empty PrevPostId") require.Equal(t, "", posts.PrevPostId, "should return an empty PrevPostId")
// similar to '/posts?before=systemPostId1' // similar to '/posts?before=systemPostId1'
posts, _, err = client.GetPostsBefore(th.BasicChannel.Id, systemPostId1, 0, 60, "", false) posts, _, err = client.GetPostsBefore(th.BasicChannel.Id, systemPostId1, 0, 60, "", false, false)
require.NoError(t, err) require.NoError(t, err)
require.Empty(t, posts.Order, "should return 0 post") require.Empty(t, posts.Order, "should return 0 post")
require.Equal(t, systemPostId1, posts.NextPostId, "should return systemPostId1 as NextPostId") require.Equal(t, systemPostId1, posts.NextPostId, "should return systemPostId1 as NextPostId")
require.Equal(t, "", posts.PrevPostId, "should return an empty PrevPostId") require.Equal(t, "", posts.PrevPostId, "should return an empty PrevPostId")
// similar to '/posts?before=systemPostId1&per_page=60&page=1' // similar to '/posts?before=systemPostId1&per_page=60&page=1'
posts, _, err = client.GetPostsBefore(th.BasicChannel.Id, systemPostId1, 1, 60, "", false) posts, _, err = client.GetPostsBefore(th.BasicChannel.Id, systemPostId1, 1, 60, "", false, false)
require.NoError(t, err) require.NoError(t, err)
require.Empty(t, posts.Order, "should return 0 posts") require.Empty(t, posts.Order, "should return 0 posts")
require.Equal(t, "", posts.NextPostId, "should return an empty NextPostId") require.Equal(t, "", posts.NextPostId, "should return an empty NextPostId")
@@ -1565,11 +1587,33 @@ func TestGetPostsBefore(t *testing.T) {
// similar to '/posts?before=non-existent-post' // similar to '/posts?before=non-existent-post'
nonExistentPostId := model.NewId() nonExistentPostId := model.NewId()
posts, _, err = client.GetPostsBefore(th.BasicChannel.Id, nonExistentPostId, 0, 60, "", false) posts, _, err = client.GetPostsBefore(th.BasicChannel.Id, nonExistentPostId, 0, 60, "", false, false)
require.NoError(t, err) require.NoError(t, err)
require.Empty(t, posts.Order, "should return 0 post") require.Empty(t, posts.Order, "should return 0 post")
require.Equal(t, nonExistentPostId, posts.NextPostId, "should return nonExistentPostId as NextPostId") require.Equal(t, nonExistentPostId, posts.NextPostId, "should return nonExistentPostId as NextPostId")
require.Equal(t, "", posts.PrevPostId, "should return an empty PrevPostId") require.Equal(t, "", posts.PrevPostId, "should return an empty PrevPostId")
client.DeletePost(post9.Id)
client.DeletePost(post8.Id)
// include deleted posts for non-admin users.
_, resp, err = client.GetPostsBefore(th.BasicChannel.Id, post9.Id, 0, 60, "", false, true)
require.Error(t, err)
CheckForbiddenStatus(t, resp)
th.TestForSystemAdminAndLocal(t, func(t *testing.T, c *model.Client4) {
// include deleted posts for admin users.
posts, resp, err = c.GetPostsBefore(th.BasicChannel.Id, post10.Id, 0, 60, "", false, true)
require.NoError(t, err)
CheckOKStatus(t, resp)
require.Len(t, posts.Order, 11, "expected 11 posts")
// not include deleted posts for admin users.
posts, resp, err = c.GetPostsBefore(th.BasicChannel.Id, post10.Id, 0, 60, "", false, false)
require.NoError(t, err)
CheckOKStatus(t, resp)
require.Len(t, posts.Order, 9, "expected 9 posts")
})
} }
func TestGetPostsAfter(t *testing.T) { func TestGetPostsAfter(t *testing.T) {
@@ -1583,7 +1627,7 @@ func TestGetPostsAfter(t *testing.T) {
post4 := th.CreatePost() post4 := th.CreatePost()
post5 := th.CreatePost() post5 := th.CreatePost()
posts, _, err := client.GetPostsAfter(th.BasicChannel.Id, post3.Id, 0, 100, "", false) posts, _, err := client.GetPostsAfter(th.BasicChannel.Id, post3.Id, 0, 100, "", false, false)
require.NoError(t, err) require.NoError(t, err)
found := make([]bool, 2) found := make([]bool, 2)
@@ -1603,18 +1647,18 @@ func TestGetPostsAfter(t *testing.T) {
require.Equal(t, "", posts.NextPostId, "should match empty NextPostId") require.Equal(t, "", posts.NextPostId, "should match empty NextPostId")
require.Equal(t, post3.Id, posts.PrevPostId, "should match PrevPostId") require.Equal(t, post3.Id, posts.PrevPostId, "should match PrevPostId")
posts, _, err = client.GetPostsAfter(th.BasicChannel.Id, post2.Id, 1, 1, "", false) posts, _, err = client.GetPostsAfter(th.BasicChannel.Id, post2.Id, 1, 1, "", false, false)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, posts.Posts, 1, "too many posts returned") require.Len(t, posts.Posts, 1, "too many posts returned")
require.Equal(t, post4.Id, posts.Order[0], "should match returned post") require.Equal(t, post4.Id, posts.Order[0], "should match returned post")
require.Equal(t, post5.Id, posts.NextPostId, "should match NextPostId") require.Equal(t, post5.Id, posts.NextPostId, "should match NextPostId")
require.Equal(t, post3.Id, posts.PrevPostId, "should match PrevPostId") require.Equal(t, post3.Id, posts.PrevPostId, "should match PrevPostId")
_, resp, err := client.GetPostsAfter(th.BasicChannel.Id, "junk", 1, 1, "", false) _, resp, err := client.GetPostsAfter(th.BasicChannel.Id, "junk", 1, 1, "", false, false)
require.Error(t, err) require.Error(t, err)
CheckBadRequestStatus(t, resp) CheckBadRequestStatus(t, resp)
posts, _, err = client.GetPostsAfter(th.BasicChannel.Id, post1.Id, 0, 3, "", false) posts, _, err = client.GetPostsAfter(th.BasicChannel.Id, post1.Id, 0, 3, "", false, false)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, posts.Posts, 3, "should match length of posts returned") require.Len(t, posts.Posts, 3, "should match length of posts returned")
require.Equal(t, post4.Id, posts.Order[0], "should match returned post") require.Equal(t, post4.Id, posts.Order[0], "should match returned post")
@@ -1622,7 +1666,7 @@ func TestGetPostsAfter(t *testing.T) {
require.Equal(t, post5.Id, posts.NextPostId, "should match NextPostId") require.Equal(t, post5.Id, posts.NextPostId, "should match NextPostId")
require.Equal(t, post1.Id, posts.PrevPostId, "should match PrevPostId") require.Equal(t, post1.Id, posts.PrevPostId, "should match PrevPostId")
posts, _, err = client.GetPostsAfter(th.BasicChannel.Id, post1.Id, 1, 3, "", false) posts, _, err = client.GetPostsAfter(th.BasicChannel.Id, post1.Id, 1, 3, "", false, false)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, posts.Posts, 1, "should match length of posts returned") require.Len(t, posts.Posts, 1, "should match length of posts returned")
require.Equal(t, post5.Id, posts.Order[0], "should match returned post") require.Equal(t, post5.Id, posts.Order[0], "should match returned post")
@@ -1638,7 +1682,7 @@ func TestGetPostsAfter(t *testing.T) {
post10 := th.CreatePost() post10 := th.CreatePost()
// similar to '/posts?after=post2' // similar to '/posts?after=post2'
posts, _, err = client.GetPostsAfter(th.BasicChannel.Id, post2.Id, 0, 60, "", false) posts, _, err = client.GetPostsAfter(th.BasicChannel.Id, post2.Id, 0, 60, "", false, false)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, posts.Order, 8, "expected 8 posts") require.Len(t, posts.Order, 8, "expected 8 posts")
require.Equal(t, post10.Id, posts.Order[0], "should match order") require.Equal(t, post10.Id, posts.Order[0], "should match order")
@@ -1647,7 +1691,7 @@ func TestGetPostsAfter(t *testing.T) {
require.Equal(t, post2.Id, posts.PrevPostId, "should return post2.Id as PrevPostId") require.Equal(t, post2.Id, posts.PrevPostId, "should return post2.Id as PrevPostId")
// similar to '/posts?after=post2&per_page=3' // similar to '/posts?after=post2&per_page=3'
posts, _, err = client.GetPostsAfter(th.BasicChannel.Id, post2.Id, 0, 3, "", false) posts, _, err = client.GetPostsAfter(th.BasicChannel.Id, post2.Id, 0, 3, "", false, false)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, posts.Order, 3, "expected 3 posts") require.Len(t, posts.Order, 3, "expected 3 posts")
require.Equal(t, post5.Id, posts.Order[0], "should match order") require.Equal(t, post5.Id, posts.Order[0], "should match order")
@@ -1656,7 +1700,7 @@ func TestGetPostsAfter(t *testing.T) {
require.Equal(t, post2.Id, posts.PrevPostId, "should return post2.Id as PrevPostId") require.Equal(t, post2.Id, posts.PrevPostId, "should return post2.Id as PrevPostId")
// similar to '/posts?after=post2&per_page=3&page=1' // similar to '/posts?after=post2&per_page=3&page=1'
posts, _, err = client.GetPostsAfter(th.BasicChannel.Id, post2.Id, 1, 3, "", false) posts, _, err = client.GetPostsAfter(th.BasicChannel.Id, post2.Id, 1, 3, "", false, false)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, posts.Order, 3, "expected 3 posts") require.Len(t, posts.Order, 3, "expected 3 posts")
require.Equal(t, post8.Id, posts.Order[0], "should match order") require.Equal(t, post8.Id, posts.Order[0], "should match order")
@@ -1665,7 +1709,7 @@ func TestGetPostsAfter(t *testing.T) {
require.Equal(t, post5.Id, posts.PrevPostId, "should return post5.Id as PrevPostId") require.Equal(t, post5.Id, posts.PrevPostId, "should return post5.Id as PrevPostId")
// similar to '/posts?after=post2&per_page=3&page=2' // similar to '/posts?after=post2&per_page=3&page=2'
posts, _, err = client.GetPostsAfter(th.BasicChannel.Id, post2.Id, 2, 3, "", false) posts, _, err = client.GetPostsAfter(th.BasicChannel.Id, post2.Id, 2, 3, "", false, false)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, posts.Order, 2, "expected 2 posts") require.Len(t, posts.Order, 2, "expected 2 posts")
require.Equal(t, post10.Id, posts.Order[0], "should match order") require.Equal(t, post10.Id, posts.Order[0], "should match order")
@@ -1674,14 +1718,14 @@ func TestGetPostsAfter(t *testing.T) {
require.Equal(t, post8.Id, posts.PrevPostId, "should return post8.Id as PrevPostId") require.Equal(t, post8.Id, posts.PrevPostId, "should return post8.Id as PrevPostId")
// similar to '/posts?after=post10' // similar to '/posts?after=post10'
posts, _, err = client.GetPostsAfter(th.BasicChannel.Id, post10.Id, 0, 60, "", false) posts, _, err = client.GetPostsAfter(th.BasicChannel.Id, post10.Id, 0, 60, "", false, false)
require.NoError(t, err) require.NoError(t, err)
require.Empty(t, posts.Order, "should return 0 post") require.Empty(t, posts.Order, "should return 0 post")
require.Equal(t, "", posts.NextPostId, "should return an empty NextPostId") require.Equal(t, "", posts.NextPostId, "should return an empty NextPostId")
require.Equal(t, post10.Id, posts.PrevPostId, "should return post10.Id as PrevPostId") require.Equal(t, post10.Id, posts.PrevPostId, "should return post10.Id as PrevPostId")
// similar to '/posts?after=post10&page=1' // similar to '/posts?after=post10&page=1'
posts, _, err = client.GetPostsAfter(th.BasicChannel.Id, post10.Id, 1, 60, "", false) posts, _, err = client.GetPostsAfter(th.BasicChannel.Id, post10.Id, 1, 60, "", false, false)
require.NoError(t, err) require.NoError(t, err)
require.Empty(t, posts.Order, "should return 0 post") require.Empty(t, posts.Order, "should return 0 post")
require.Equal(t, "", posts.NextPostId, "should return an empty NextPostId") require.Equal(t, "", posts.NextPostId, "should return an empty NextPostId")
@@ -1689,11 +1733,33 @@ func TestGetPostsAfter(t *testing.T) {
// similar to '/posts?after=non-existent-post' // similar to '/posts?after=non-existent-post'
nonExistentPostId := model.NewId() nonExistentPostId := model.NewId()
posts, _, err = client.GetPostsAfter(th.BasicChannel.Id, nonExistentPostId, 0, 60, "", false) posts, _, err = client.GetPostsAfter(th.BasicChannel.Id, nonExistentPostId, 0, 60, "", false, false)
require.NoError(t, err) require.NoError(t, err)
require.Empty(t, posts.Order, "should return 0 post") require.Empty(t, posts.Order, "should return 0 post")
require.Equal(t, "", posts.NextPostId, "should return an empty NextPostId") require.Equal(t, "", posts.NextPostId, "should return an empty NextPostId")
require.Equal(t, nonExistentPostId, posts.PrevPostId, "should return nonExistentPostId as PrevPostId") require.Equal(t, nonExistentPostId, posts.PrevPostId, "should return nonExistentPostId as PrevPostId")
client.DeletePost(post10.Id)
client.DeletePost(post9.Id)
// include deleted posts for non-admin users.
_, resp, err = client.GetPostsAfter(th.BasicChannel.Id, post1.Id, 0, 60, "", false, true)
require.Error(t, err)
CheckForbiddenStatus(t, resp)
th.TestForSystemAdminAndLocal(t, func(t *testing.T, c *model.Client4) {
// include deleted posts for admin users.
posts, resp, err = c.GetPostsAfter(th.BasicChannel.Id, post1.Id, 0, 60, "", false, true)
require.NoError(t, err)
CheckOKStatus(t, resp)
require.Len(t, posts.Order, 9, "expected 9 posts")
// not include deleted posts for admin users.
posts, resp, err = c.GetPostsAfter(th.BasicChannel.Id, post1.Id, 0, 60, "", false, false)
require.NoError(t, err)
CheckOKStatus(t, resp)
require.Len(t, posts.Order, 7, "expected 7 posts")
})
} }
func TestGetPostsForChannelAroundLastUnread(t *testing.T) { func TestGetPostsForChannelAroundLastUnread(t *testing.T) {
@@ -1798,7 +1864,7 @@ func TestGetPostsForChannelAroundLastUnread(t *testing.T) {
require.Len(t, posts.Order, 12, "Should return 12 posts only since there's no unread post") require.Len(t, posts.Order, 12, "Should return 12 posts only since there's no unread post")
// get the first system post generated before the created posts above // get the first system post generated before the created posts above
posts, _, err = client.GetPostsBefore(th.BasicChannel.Id, post1.Id, 0, 2, "", false) posts, _, err = client.GetPostsBefore(th.BasicChannel.Id, post1.Id, 0, 2, "", false, false)
require.NoError(t, err) require.NoError(t, err)
systemPost0 := posts.Posts[posts.Order[0]] systemPost0 := posts.Posts[posts.Order[0]]
postIdNames[systemPost0.Id] = "system post 0" postIdNames[systemPost0.Id] = "system post 0"

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

@@ -3028,7 +3028,7 @@ func TestImportTeam(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, importedChannel.Name, "general", "names did not match expected: general") require.Equal(t, importedChannel.Name, "general", "names did not match expected: general")
posts, _, err := th.SystemAdminClient.GetPostsForChannel(importedChannel.Id, 0, 60, "", false) posts, _, err := th.SystemAdminClient.GetPostsForChannel(importedChannel.Id, 0, 60, "", false, false)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, posts.Posts[posts.Order[3]].Message, "This is a test post to test the import process", "missing posts in the import process") require.Equal(t, posts.Posts[posts.Order[3]].Message, "This is a test post to test the import process", "missing posts in the import process")
}) })

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

@@ -3925,11 +3925,15 @@ func (c *Client4) GetPostThreadWithOpts(postID string, etag string, opts GetPost
} }
// GetPostsForChannel gets a page of posts with an array for ordering for a channel. // GetPostsForChannel gets a page of posts with an array for ordering for a channel.
func (c *Client4) GetPostsForChannel(channelId string, page, perPage int, etag string, collapsedThreads bool) (*PostList, *Response, error) { func (c *Client4) GetPostsForChannel(channelId string, page, perPage int, etag string, collapsedThreads bool, includeDeleted bool) (*PostList, *Response, error) {
query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
if collapsedThreads { if collapsedThreads {
query += "&collapsedThreads=true" query += "&collapsedThreads=true"
} }
if includeDeleted {
query += "&include_deleted=true"
}
r, err := c.DoAPIGet(c.channelRoute(channelId)+"/posts"+query, etag) r, err := c.DoAPIGet(c.channelRoute(channelId)+"/posts"+query, etag)
if err != nil { if err != nil {
return nil, BuildResponse(r), err return nil, BuildResponse(r), err
@@ -4050,11 +4054,14 @@ func (c *Client4) GetPostsSince(channelId string, time int64, collapsedThreads b
} }
// GetPostsAfter gets a page of posts that were posted after the post provided. // GetPostsAfter gets a page of posts that were posted after the post provided.
func (c *Client4) GetPostsAfter(channelId, postId string, page, perPage int, etag string, collapsedThreads bool) (*PostList, *Response, error) { func (c *Client4) GetPostsAfter(channelId, postId string, page, perPage int, etag string, collapsedThreads bool, includeDeleted bool) (*PostList, *Response, error) {
query := fmt.Sprintf("?page=%v&per_page=%v&after=%v", page, perPage, postId) query := fmt.Sprintf("?page=%v&per_page=%v&after=%v", page, perPage, postId)
if collapsedThreads { if collapsedThreads {
query += "&collapsedThreads=true" query += "&collapsedThreads=true"
} }
if includeDeleted {
query += "&include_deleted=true"
}
r, err := c.DoAPIGet(c.channelRoute(channelId)+"/posts"+query, etag) r, err := c.DoAPIGet(c.channelRoute(channelId)+"/posts"+query, etag)
if err != nil { if err != nil {
return nil, BuildResponse(r), err return nil, BuildResponse(r), err
@@ -4071,11 +4078,14 @@ func (c *Client4) GetPostsAfter(channelId, postId string, page, perPage int, eta
} }
// GetPostsBefore gets a page of posts that were posted before the post provided. // GetPostsBefore gets a page of posts that were posted before the post provided.
func (c *Client4) GetPostsBefore(channelId, postId string, page, perPage int, etag string, collapsedThreads bool) (*PostList, *Response, error) { func (c *Client4) GetPostsBefore(channelId, postId string, page, perPage int, etag string, collapsedThreads bool, includeDeleted bool) (*PostList, *Response, error) {
query := fmt.Sprintf("?page=%v&per_page=%v&before=%v", page, perPage, postId) query := fmt.Sprintf("?page=%v&per_page=%v&before=%v", page, perPage, postId)
if collapsedThreads { if collapsedThreads {
query += "&collapsedThreads=true" query += "&collapsedThreads=true"
} }
if includeDeleted {
query += "&include_deleted=true"
}
r, err := c.DoAPIGet(c.channelRoute(channelId)+"/posts"+query, etag) r, err := c.DoAPIGet(c.channelRoute(channelId)+"/posts"+query, etag)
if err != nil { if err != nil {
return nil, BuildResponse(r), err return nil, BuildResponse(r), err

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

@@ -73,6 +73,7 @@ var PermissionDeleteOthersEmojis *Permission
var PermissionCreatePost *Permission var PermissionCreatePost *Permission
var PermissionCreatePostPublic *Permission var PermissionCreatePostPublic *Permission
var PermissionCreatePostEphemeral *Permission var PermissionCreatePostEphemeral *Permission
var PermissionReadDeletedPosts *Permission
var PermissionEditPost *Permission var PermissionEditPost *Permission
var PermissionEditOthersPosts *Permission var PermissionEditOthersPosts *Permission
var PermissionDeletePost *Permission var PermissionDeletePost *Permission
@@ -708,6 +709,12 @@ func initializePermissions() {
"authentication.permissions.create_post_ephemeral.description", "authentication.permissions.create_post_ephemeral.description",
PermissionScopeChannel, PermissionScopeChannel,
} }
PermissionReadDeletedPosts = &Permission{
"read_deleted_posts",
"authentication.permissions.read_deleted_posts.name",
"authentication.permissions.read_deleted_posts.description",
PermissionScopeChannel,
}
PermissionEditPost = &Permission{ PermissionEditPost = &Permission{
"edit_post", "edit_post",
"authentication.permissions.edit_post.name", "authentication.permissions.edit_post.name",
@@ -2302,6 +2309,7 @@ func initializePermissions() {
PermissionCreatePost, PermissionCreatePost,
PermissionCreatePostPublic, PermissionCreatePostPublic,
PermissionCreatePostEphemeral, PermissionCreatePostEphemeral,
PermissionReadDeletedPosts,
PermissionEditPost, PermissionEditPost,
PermissionEditOthersPosts, PermissionEditOthersPosts,
PermissionDeletePost, PermissionDeletePost,

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

@@ -304,6 +304,7 @@ type GetPostsOptions struct {
FromPost string // PostId after which to send the items FromPost string // PostId after which to send the items
FromCreateAt int64 // CreateAt after which to send the items FromCreateAt int64 // CreateAt after which to send the items
Direction string // Only accepts up|down. Indicates the order in which to send the items. Direction string // Only accepts up|down. Indicates the order in which to send the items.
IncludeDeleted bool
} }
type PostCountOptions struct { type PostCountOptions struct {

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

@@ -1168,13 +1168,13 @@ func (s *SqlPostStore) GetPosts(options model.GetPostsOptions, _ bool, sanitizeO
rpc := make(chan store.StoreResult, 1) rpc := make(chan store.StoreResult, 1)
go func() { go func() {
posts, err := s.getRootPosts(options.ChannelId, offset, options.PerPage, options.SkipFetchThreads) posts, err := s.getRootPosts(options.ChannelId, offset, options.PerPage, options.SkipFetchThreads, options.IncludeDeleted)
rpc <- store.StoreResult{Data: posts, NErr: err} rpc <- store.StoreResult{Data: posts, NErr: err}
close(rpc) close(rpc)
}() }()
cpc := make(chan store.StoreResult, 1) cpc := make(chan store.StoreResult, 1)
go func() { go func() {
posts, err := s.getParentsPosts(options.ChannelId, offset, options.PerPage, options.SkipFetchThreads) posts, err := s.getParentsPosts(options.ChannelId, offset, options.PerPage, options.SkipFetchThreads, options.IncludeDeleted)
cpc <- store.StoreResult{Data: posts, NErr: err} cpc <- store.StoreResult{Data: posts, NErr: err}
close(cpc) close(cpc)
}() }()
@@ -1440,13 +1440,18 @@ func (s *SqlPostStore) getPostsAround(before bool, options model.GetPostsOptions
) )
} }
query := s.getQueryBuilder().Select(columns...) query := s.getQueryBuilder().Select(columns...)
replyCountSubQuery := s.getQueryBuilder().Select("COUNT(*)").From("Posts").Where(sq.Expr("Posts.RootId = (CASE WHEN p.RootId = '' THEN p.Id ELSE p.RootId END) AND Posts.DeleteAt = 0")) replyCountSubQuery := s.getQueryBuilder().Select("COUNT(*)").From("Posts").Where(sq.Expr("Posts.RootId = (CASE WHEN p.RootId = '' THEN p.Id ELSE p.RootId END)"))
conditions := sq.And{ conditions := sq.And{
sq.Expr(`CreateAt `+direction+` (SELECT CreateAt FROM Posts WHERE Id = ?)`, options.PostId), sq.Expr(`CreateAt `+direction+` (SELECT CreateAt FROM Posts WHERE Id = ?)`, options.PostId),
sq.Eq{"p.ChannelId": options.ChannelId}, sq.Eq{"p.ChannelId": options.ChannelId},
sq.Eq{"p.DeleteAt": int(0)},
} }
if !options.IncludeDeleted {
replyCountSubQuery = replyCountSubQuery.Where(sq.Expr("Posts.DeleteAt = 0"))
conditions = append(conditions, sq.Eq{"p.DeleteAt": int(0)})
}
if options.CollapsedThreads { if options.CollapsedThreads {
conditions = append(conditions, sq.Eq{"RootId": ""}) conditions = append(conditions, sq.Eq{"RootId": ""})
query = query.LeftJoin("Threads ON Threads.PostId = p.Id").LeftJoin("ThreadMemberships ON ThreadMemberships.PostId = p.Id AND ThreadMemberships.UserId=?", options.UserId) query = query.LeftJoin("Threads ON Threads.PostId = p.Id").LeftJoin("ThreadMemberships ON ThreadMemberships.PostId = p.Id AND ThreadMemberships.UserId=?", options.UserId)
@@ -1492,10 +1497,13 @@ func (s *SqlPostStore) getPostsAround(before bool, options model.GetPostsOptions
Where(sq.And{ Where(sq.And{
idQuery, idQuery,
sq.Eq{"p.ChannelId": options.ChannelId}, sq.Eq{"p.ChannelId": options.ChannelId},
sq.Eq{"p.DeleteAt": 0},
}). }).
OrderBy("CreateAt DESC") OrderBy("CreateAt DESC")
if !options.IncludeDeleted {
rootQuery = rootQuery.Where(sq.Eq{"p.DeleteAt": 0})
}
rootQueryString, rootArgs, nErr := rootQuery.ToSql() rootQueryString, rootArgs, nErr := rootQuery.ToSql()
if nErr != nil { if nErr != nil {
@@ -1620,14 +1628,21 @@ func (s *SqlPostStore) GetPostAfterTime(channelId string, time int64, collapsedT
return &post, nil return &post, nil
} }
func (s *SqlPostStore) getRootPosts(channelId string, offset int, limit int, skipFetchThreads bool) ([]*model.Post, error) { func (s *SqlPostStore) getRootPosts(channelId string, offset int, limit int, skipFetchThreads bool, includeDeleted bool) ([]*model.Post, error) {
posts := []*model.Post{} posts := []*model.Post{}
var fetchQuery string var fetchQuery string
if skipFetchThreads { if skipFetchThreads {
fetchQuery = "SELECT p.*, (SELECT COUNT(*) FROM Posts WHERE Posts.RootId = (CASE WHEN p.RootId = '' THEN p.Id ELSE p.RootId END) AND Posts.DeleteAt = 0) as ReplyCount FROM Posts p WHERE p.ChannelId = ? AND p.DeleteAt = 0 ORDER BY p.CreateAt DESC LIMIT ? OFFSET ?" fetchQuery = "SELECT p.*, (SELECT COUNT(*) FROM Posts WHERE Posts.RootId = (CASE WHEN p.RootId = '' THEN p.Id ELSE p.RootId END)) as ReplyCount FROM Posts p WHERE p.ChannelId = ? ORDER BY p.CreateAt DESC LIMIT ? OFFSET ?"
if !includeDeleted {
fetchQuery = "SELECT p.*, (SELECT COUNT(*) FROM Posts WHERE Posts.RootId = (CASE WHEN p.RootId = '' THEN p.Id ELSE p.RootId END) AND Posts.DeleteAt = 0) as ReplyCount FROM Posts p WHERE p.ChannelId = ? AND p.DeleteAt = 0 ORDER BY p.CreateAt DESC LIMIT ? OFFSET ?"
}
} else { } else {
fetchQuery = "SELECT * FROM Posts WHERE Posts.ChannelId = ? AND Posts.DeleteAt = 0 ORDER BY Posts.CreateAt DESC LIMIT ? OFFSET ?" fetchQuery = "SELECT * FROM Posts WHERE Posts.ChannelId = ? ORDER BY Posts.CreateAt DESC LIMIT ? OFFSET ?"
if !includeDeleted {
fetchQuery = "SELECT * FROM Posts WHERE Posts.ChannelId = ? AND Posts.DeleteAt = 0 ORDER BY Posts.CreateAt DESC LIMIT ? OFFSET ?"
}
} }
err := s.GetReplicaX().Select(&posts, fetchQuery, channelId, limit, offset) err := s.GetReplicaX().Select(&posts, fetchQuery, channelId, limit, offset)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "failed to find Posts") return nil, errors.Wrap(err, "failed to find Posts")
@@ -1635,9 +1650,14 @@ func (s *SqlPostStore) getRootPosts(channelId string, offset int, limit int, ski
return posts, nil return posts, nil
} }
func (s *SqlPostStore) getParentsPosts(channelId string, offset int, limit int, skipFetchThreads bool) ([]*model.Post, error) { func (s *SqlPostStore) getParentsPosts(channelId string, offset int, limit int, skipFetchThreads bool, includeDeleted bool) ([]*model.Post, error) {
if s.DriverName() == model.DatabaseDriverPostgres { if s.DriverName() == model.DatabaseDriverPostgres {
return s.getParentsPostsPostgreSQL(channelId, offset, limit, skipFetchThreads) return s.getParentsPostsPostgreSQL(channelId, offset, limit, skipFetchThreads, includeDeleted)
}
deleteAtCondition := "AND DeleteAt = 0"
if includeDeleted {
deleteAtCondition = ""
} }
// query parent Ids first // query parent Ids first
@@ -1651,9 +1671,8 @@ func (s *SqlPostStore) getParentsPosts(channelId string, offset int, limit int,
FROM FROM
Posts Posts
WHERE WHERE
Posts.ChannelId = ? ChannelId = ? ` + deleteAtCondition + `
AND Posts.DeleteAt = 0 ORDER BY CreateAt DESC
ORDER BY Posts.CreateAt DESC
LIMIT ? OFFSET ?) q LIMIT ? OFFSET ?) q
WHERE q.RootId != ''` WHERE q.RootId != ''`
@@ -1669,7 +1688,11 @@ func (s *SqlPostStore) getParentsPosts(channelId string, offset int, limit int,
var where sq.Sqlizer var where sq.Sqlizer
where = sq.Eq{"p.Id": roots} where = sq.Eq{"p.Id": roots}
if skipFetchThreads { if skipFetchThreads {
cols = append(cols, "(SELECT COUNT(*) FROM Posts WHERE Posts.RootId = (CASE WHEN p.RootId = '' THEN p.Id ELSE p.RootId END) AND Posts.DeleteAt = 0) as ReplyCount") col := "(SELECT COUNT(*) FROM Posts WHERE Posts.RootId = (CASE WHEN p.RootId = '' THEN p.Id ELSE p.RootId END)) as ReplyCount"
if !includeDeleted {
col = "(SELECT COUNT(*) FROM Posts WHERE Posts.RootId = (CASE WHEN p.RootId = '' THEN p.Id ELSE p.RootId END) AND Posts.DeleteAt = 0) as ReplyCount"
}
cols = append(cols, col)
} else { } else {
where = sq.Or{ where = sq.Or{
where, where,
@@ -1683,10 +1706,13 @@ func (s *SqlPostStore) getParentsPosts(channelId string, offset int, limit int,
Where(sq.And{ Where(sq.And{
where, where,
sq.Eq{"p.ChannelId": channelId}, sq.Eq{"p.ChannelId": channelId},
sq.Eq{"p.DeleteAt": 0},
}). }).
OrderBy("p.CreateAt") OrderBy("p.CreateAt")
if !includeDeleted {
query = query.Where(sq.Eq{"p.DeleteAt": 0})
}
sql, args, err := query.ToSql() sql, args, err := query.ToSql()
if err != nil { if err != nil {
return nil, errors.Wrap(err, "ParentPosts_Tosql") return nil, errors.Wrap(err, "ParentPosts_Tosql")
@@ -1700,15 +1726,25 @@ func (s *SqlPostStore) getParentsPosts(channelId string, offset int, limit int,
return posts, nil return posts, nil
} }
func (s *SqlPostStore) getParentsPostsPostgreSQL(channelId string, offset int, limit int, skipFetchThreads bool) ([]*model.Post, error) { func (s *SqlPostStore) getParentsPostsPostgreSQL(channelId string, offset int, limit int, skipFetchThreads bool, includeDeleted bool) ([]*model.Post, error) {
posts := []*model.Post{} posts := []*model.Post{}
replyCountQuery := "" replyCountQuery := ""
onStatement := "q1.RootId = q2.Id" onStatement := "q1.RootId = q2.Id"
if skipFetchThreads { if skipFetchThreads {
replyCountQuery = ` ,(SELECT COUNT(*) FROM Posts WHERE Posts.RootId = (CASE WHEN q2.RootId = '' THEN q2.Id ELSE q2.RootId END) AND Posts.DeleteAt = 0) as ReplyCount` replyCountQuery = ` ,(SELECT COUNT(*) FROM Posts WHERE Posts.RootId = (CASE WHEN q2.RootId = '' THEN q2.Id ELSE q2.RootId END)) as ReplyCount`
if !includeDeleted {
replyCountQuery = ` ,(SELECT COUNT(*) FROM Posts WHERE Posts.RootId = (CASE WHEN q2.RootId = '' THEN q2.Id ELSE q2.RootId END) AND Posts.DeleteAt = 0) as ReplyCount`
}
} else { } else {
onStatement += " OR q1.RootId = q2.RootId" onStatement += " OR q1.RootId = q2.RootId"
} }
deleteAtQueryCondition := "AND q2.DeleteAt = 0"
deleteAtSubQueryCondition := "AND Posts.DeleteAt = 0"
if includeDeleted {
deleteAtQueryCondition, deleteAtSubQueryCondition = "", ""
}
err := s.GetReplicaX().Select(&posts, err := s.GetReplicaX().Select(&posts,
`SELECT q2.*`+replyCountQuery+` `SELECT q2.*`+replyCountQuery+`
FROM FROM
@@ -1722,15 +1758,13 @@ func (s *SqlPostStore) getParentsPostsPostgreSQL(channelId string, offset int, l
FROM FROM
Posts Posts
WHERE WHERE
Posts.ChannelId = ? Posts.ChannelId = ? `+deleteAtSubQueryCondition+`
AND Posts.DeleteAt = 0
ORDER BY Posts.CreateAt DESC ORDER BY Posts.CreateAt DESC
LIMIT ? OFFSET ?) q3 LIMIT ? OFFSET ?) q3
WHERE q3.RootId != '') q1 WHERE q3.RootId != '') q1
ON `+onStatement+` ON `+onStatement+`
WHERE WHERE
q2.ChannelId = ? q2.ChannelId = ? `+deleteAtQueryCondition+`
AND q2.DeleteAt = 0
ORDER BY q2.CreateAt`, channelId, limit, offset, channelId) ORDER BY q2.CreateAt`, channelId, limit, offset, channelId)
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "failed to find Posts with channelId=%s", channelId) return nil, errors.Wrapf(err, "failed to find Posts with channelId=%s", channelId)

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

@@ -1946,6 +1946,73 @@ func testPostStoreGetPosts(t *testing.T, ss store.Store) {
assert.Equal(t, int64(1), postList.Posts[post5.Id].ReplyCount) assert.Equal(t, int64(1), postList.Posts[post5.Id].ReplyCount)
assert.Equal(t, int64(1), postList.Posts[post6.Id].ReplyCount) assert.Equal(t, int64(1), postList.Posts[post6.Id].ReplyCount)
}) })
t.Run("should return all posts in a channel included deleted posts", func(t *testing.T) {
err := ss.Post().Delete(post1.Id, 1, userId)
require.NoError(t, err)
postList, err := ss.Post().GetPosts(model.GetPostsOptions{ChannelId: channelId, Page: 0, PerPage: 30, SkipFetchThreads: false, IncludeDeleted: true}, false, map[string]bool{})
require.NoError(t, err)
assert.Equal(t, []string{
post6.Id,
post5.Id,
post4.Id,
post3.Id,
post2.Id,
post1.Id,
}, postList.Order)
assert.Len(t, postList.Posts, 6)
assert.NotNil(t, postList.Posts[post1.Id])
assert.NotNil(t, postList.Posts[post2.Id])
assert.NotNil(t, postList.Posts[post3.Id])
assert.NotNil(t, postList.Posts[post4.Id])
assert.NotNil(t, postList.Posts[post5.Id])
assert.NotNil(t, postList.Posts[post6.Id])
})
t.Run("should return all posts in a channel included deleted posts without threads", func(t *testing.T) {
err := ss.Post().Delete(post5.Id, 1, userId)
require.NoError(t, err)
postList, err := ss.Post().GetPosts(model.GetPostsOptions{ChannelId: channelId, Page: 0, PerPage: 30, SkipFetchThreads: true, IncludeDeleted: true}, false, map[string]bool{})
require.NoError(t, err)
assert.Equal(t, []string{
post6.Id,
post5.Id,
post4.Id,
post3.Id,
post2.Id,
post1.Id,
}, postList.Order)
assert.Len(t, postList.Posts, 6)
assert.NotNil(t, postList.Posts[post5.Id])
assert.NotNil(t, postList.Posts[post6.Id])
assert.Equal(t, int64(1), postList.Posts[post5.Id].ReplyCount)
assert.Equal(t, int64(1), postList.Posts[post6.Id].ReplyCount)
})
t.Run("should return the lasts posts created in channel without include deleted posts", func(t *testing.T) {
err := ss.Post().Delete(post6.Id, 1, userId)
require.NoError(t, err)
postList, err := ss.Post().GetPosts(model.GetPostsOptions{ChannelId: channelId, Page: 0, PerPage: 30, SkipFetchThreads: true, IncludeDeleted: false}, false, map[string]bool{})
require.NoError(t, err)
assert.Equal(t, []string{
post4.Id,
post3.Id,
post2.Id,
}, postList.Order)
assert.Len(t, postList.Posts, 3)
assert.NotNil(t, postList.Posts[post2.Id])
assert.NotNil(t, postList.Posts[post3.Id])
assert.NotNil(t, postList.Posts[post4.Id])
})
} }
func testPostStoreGetPostBeforeAfter(t *testing.T, ss store.Store) { func testPostStoreGetPostBeforeAfter(t *testing.T, ss store.Store) {