MM-11210 Add "GET /posts/unread" API to support landing on the last unread post (#11486)

* [MM-11210] Add API GET 'api/v4/channels/{channel_id:[A-Za-z0-9]+}/posts/unread' for scrolling overhaul (#9108)

* Add API GET 'api/v4/channels/{channel_id:[A-Za-z0-9]+}/posts/unread'

* add constants

* refactor GetPostSince and added more tests

* move constants to app package

* [MM-11528 &&  MM-11583] Add userId to in the "posts/unread" path and update test with time delay to fix intermittent failure (#9229)

* add userId to in the "posts/unread" path and update test with time delay to fix intermittent failure

* add limit before and after to query

* remove time delay on test and put pretermined value of Post.CreateAt

* Fix conflict

* [MM-11876] Add cursor to posts list such as next_post_id and previous_post_id (#9707)

* add cursor to posts list such as next_post_id and previous_post_id

add publish previous_post_id on WEBSOCKET_EVENT_POSTED and only get next or previous post IDs if necessary

revert change on adding previous_post_id in WEBSOCKET_EVENT_POSTED

add missing strings import

fix merge conflicts

* update per comment

* update per feedback

* corrected the logic in getting the next and previous post ID

* fix logic to determine next and post IDs, and rename function to have suffix of "Time"

* rearrange logics and add mote tests

* fix merge conflict

* fix missing message when using unread API (#10233)

* MM-15569 Fixes failing test on TestGetPostsForChannelAroundLastUnread (#11039)

* Fix missing posts when getting posts since

* revert changes to GetPostsSince

* migrate Post.GetPostAfterTime and Post.GetPostBeforeTime to sync by default

* revert change to cacheItem

* Fix post ID validation, build query on squirrel and only return post ID as necessary
Этот коммит содержится в:
Saturnino Abril
2019-07-04 05:23:04 +08:00
коммит произвёл Sudheer
родитель f56a8f5a99
Коммит b832985f1d
12 изменённых файлов: 1085 добавлений и 32 удалений

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

@@ -9,6 +9,7 @@ import (
"strconv"
"time"
"github.com/mattermost/mattermost-server/app"
"github.com/mattermost/mattermost-server/model"
)
@@ -22,6 +23,8 @@ func (api *API) InitPost() {
api.BaseRoutes.PostsForChannel.Handle("", api.ApiSessionRequired(getPostsForChannel)).Methods("GET")
api.BaseRoutes.PostsForUser.Handle("/flagged", api.ApiSessionRequired(getFlaggedPostsForUser)).Methods("GET")
api.BaseRoutes.ChannelForUser.Handle("/posts/unread", api.ApiSessionRequired(getPostsForChannelAroundLastUnread)).Methods("GET")
api.BaseRoutes.Team.Handle("/posts/search", api.ApiSessionRequired(searchPosts)).Methods("POST")
api.BaseRoutes.Post.Handle("", api.ApiSessionRequired(updatePost)).Methods("PUT")
api.BaseRoutes.Post.Handle("/patch", api.ApiSessionRequired(patchPost)).Methods("PUT")
@@ -109,12 +112,20 @@ func getPostsForChannel(c *Context, w http.ResponseWriter, r *http.Request) {
}
afterPost := r.URL.Query().Get("after")
beforePost := r.URL.Query().Get("before")
sinceString := r.URL.Query().Get("since")
if len(afterPost) > 0 && !model.IsValidId(afterPost) {
c.SetInvalidParam("after")
return
}
beforePost := r.URL.Query().Get("before")
if len(beforePost) > 0 && !model.IsValidId(beforePost) {
c.SetInvalidParam("before")
return
}
sinceString := r.URL.Query().Get("since")
var since int64
var parseError error
if len(sinceString) > 0 {
since, parseError = strconv.ParseInt(sinceString, 10, 64)
if parseError != nil {
@@ -123,7 +134,11 @@ func getPostsForChannel(c *Context, w http.ResponseWriter, r *http.Request) {
}
}
if !c.App.SessionHasPermissionToChannel(c.App.Session, c.Params.ChannelId, model.PERMISSION_READ_CHANNEL) {
channelId := c.Params.ChannelId
page := c.Params.Page
perPage := c.Params.PerPage
if !c.App.SessionHasPermissionToChannel(c.App.Session, channelId, model.PERMISSION_READ_CHANNEL) {
c.SetPermissionError(model.PERMISSION_READ_CHANNEL)
return
}
@@ -133,31 +148,31 @@ func getPostsForChannel(c *Context, w http.ResponseWriter, r *http.Request) {
etag := ""
if since > 0 {
list, err = c.App.GetPostsSince(c.Params.ChannelId, since)
list, err = c.App.GetPostsSince(channelId, since)
} else if len(afterPost) > 0 {
etag = c.App.GetPostsEtag(c.Params.ChannelId)
etag = c.App.GetPostsEtag(channelId)
if c.HandleEtag(etag, "Get Posts After", w, r) {
return
}
list, err = c.App.GetPostsAfterPost(c.Params.ChannelId, afterPost, c.Params.Page, c.Params.PerPage)
list, err = c.App.GetPostsAfterPost(channelId, afterPost, page, perPage)
} else if len(beforePost) > 0 {
etag = c.App.GetPostsEtag(c.Params.ChannelId)
etag = c.App.GetPostsEtag(channelId)
if c.HandleEtag(etag, "Get Posts Before", w, r) {
return
}
list, err = c.App.GetPostsBeforePost(c.Params.ChannelId, beforePost, c.Params.Page, c.Params.PerPage)
list, err = c.App.GetPostsBeforePost(channelId, beforePost, page, perPage)
} else {
etag = c.App.GetPostsEtag(c.Params.ChannelId)
etag = c.App.GetPostsEtag(channelId)
if c.HandleEtag(etag, "Get Posts", w, r) {
return
}
list, err = c.App.GetPostsPage(c.Params.ChannelId, c.Params.Page, c.Params.PerPage)
list, err = c.App.GetPostsPage(channelId, page, perPage)
}
if err != nil {
@@ -169,7 +184,56 @@ func getPostsForChannel(c *Context, w http.ResponseWriter, r *http.Request) {
w.Header().Set(model.HEADER_ETAG_SERVER, etag)
}
w.Write([]byte(c.App.PreparePostListForClient(list).ToJson()))
c.App.AddCursorIdsForPostList(list, afterPost, beforePost, since, page, perPage)
clientPostList := c.App.PreparePostListForClient(list)
w.Write([]byte(clientPostList.ToJson()))
}
func getPostsForChannelAroundLastUnread(c *Context, w http.ResponseWriter, r *http.Request) {
c.RequireUserId().RequireChannelId()
if c.Err != nil {
return
}
userId := c.Params.UserId
if !c.App.SessionHasPermissionToUser(c.App.Session, userId) {
c.SetPermissionError(model.PERMISSION_EDIT_OTHER_USERS)
return
}
channelId := c.Params.ChannelId
if !c.App.SessionHasPermissionToChannel(c.App.Session, channelId, model.PERMISSION_READ_CHANNEL) {
c.SetPermissionError(model.PERMISSION_READ_CHANNEL)
return
}
postList, err := c.App.GetPostsForChannelAroundLastUnread(channelId, userId, c.Params.LimitBefore, c.Params.LimitAfter)
if err != nil {
c.Err = err
return
}
etag := ""
if len(postList.Order) == 0 {
etag = c.App.GetPostsEtag(channelId)
if c.HandleEtag(etag, "Get Posts", w, r) {
return
}
postList, err = c.App.GetPostsPage(channelId, app.PAGE_DEFAULT, c.Params.LimitBefore)
}
postList.NextPostId = c.App.GetNextPostIdFromPostList(postList)
postList.PrevPostId = c.App.GetPrevPostIdFromPostList(postList)
clientPostList := c.App.PreparePostListForClient(postList)
if len(etag) > 0 {
w.Header().Set(model.HEADER_ETAG_SERVER, etag)
}
w.Write([]byte(clientPostList.ToJson()))
}
func getFlaggedPostsForUser(c *Context, w http.ResponseWriter, r *http.Request) {