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 удалений

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

@@ -20,6 +20,7 @@ import (
const (
PENDING_POST_IDS_CACHE_SIZE = 25000
PENDING_POST_IDS_CACHE_TTL = 30 * time.Second
PAGE_DEFAULT = 0
)
func (a *App) CreatePostAsUser(post *model.Post, currentSessionId string) (*model.Post, *model.AppError) {
@@ -674,6 +675,126 @@ func (a *App) GetPostsAroundPost(postId, channelId string, offset, limit int, be
return a.Srv.Store.Post().GetPostsAfter(channelId, postId, limit, offset)
}
func (a *App) GetPostAfterTime(channelId string, time int64) (*model.Post, *model.AppError) {
return a.Srv.Store.Post().GetPostAfterTime(channelId, time)
}
func (a *App) GetPostIdAfterTime(channelId string, time int64) (string, *model.AppError) {
return a.Srv.Store.Post().GetPostIdAfterTime(channelId, time)
}
func (a *App) GetPostIdBeforeTime(channelId string, time int64) (string, *model.AppError) {
return a.Srv.Store.Post().GetPostIdBeforeTime(channelId, time)
}
func (a *App) GetNextPostIdFromPostList(postList *model.PostList) string {
if len(postList.Order) > 0 {
firstPostId := postList.Order[0]
firstPost := postList.Posts[firstPostId]
nextPostId, err := a.GetPostIdAfterTime(firstPost.ChannelId, firstPost.CreateAt)
if err != nil {
mlog.Warn("GetNextPostIdFromPostList: failed in getting next post", mlog.Err(err))
}
return nextPostId
}
return ""
}
func (a *App) GetPrevPostIdFromPostList(postList *model.PostList) string {
if len(postList.Order) > 0 {
lastPostId := postList.Order[len(postList.Order)-1]
lastPost := postList.Posts[lastPostId]
previousPostId, err := a.GetPostIdBeforeTime(lastPost.ChannelId, lastPost.CreateAt)
if err != nil {
mlog.Warn("GetPrevPostIdFromPostList: failed in getting previous post", mlog.Err(err))
}
return previousPostId
}
return ""
}
// AddCursorIdsForPostList adds NextPostId and PrevPostId as cursor to the PostList.
// The conditional blocks ensure that it sets those cursor IDs immediately as afterPost, beforePost or empty,
// and only query to database whenever necessary.
func (a *App) AddCursorIdsForPostList(originalList *model.PostList, afterPost, beforePost string, since int64, page, perPage int) {
prevPostIdSet := false
prevPostId := ""
nextPostIdSet := false
nextPostId := ""
if since > 0 { // "since" query to return empty NextPostId and PrevPostId
nextPostIdSet = true
prevPostIdSet = true
} else if afterPost != "" {
if page == 0 {
prevPostId = afterPost
prevPostIdSet = true
}
if len(originalList.Order) < perPage {
nextPostIdSet = true
}
} else if beforePost != "" {
if page == 0 {
nextPostId = beforePost
nextPostIdSet = true
}
if len(originalList.Order) < perPage {
prevPostIdSet = true
}
}
if !nextPostIdSet {
nextPostId = a.GetNextPostIdFromPostList(originalList)
}
if !prevPostIdSet {
prevPostId = a.GetPrevPostIdFromPostList(originalList)
}
originalList.NextPostId = nextPostId
originalList.PrevPostId = prevPostId
}
func (a *App) GetPostsForChannelAroundLastUnread(channelId, userId string, limitBefore, limitAfter int) (*model.PostList, *model.AppError) {
var member *model.ChannelMember
var err *model.AppError
if member, err = a.GetChannelMember(channelId, userId); err != nil {
return nil, err
} else if member.LastViewedAt == 0 {
return model.NewPostList(), nil
}
lastUnreadPost, err := a.GetPostAfterTime(channelId, member.LastViewedAt)
if err != nil {
return nil, err
} else if lastUnreadPost == nil {
return model.NewPostList(), nil
}
var postList *model.PostList
if postList, err = a.GetPostsBeforePost(channelId, lastUnreadPost.Id, PAGE_DEFAULT, limitBefore); err != nil {
return nil, err
}
if postListAfter, err := a.GetPostsAfterPost(channelId, lastUnreadPost.Id, PAGE_DEFAULT, limitAfter-1); err != nil {
return nil, err
} else if postListAfter != nil {
postList.Extend(postListAfter)
}
postList.AddPost(lastUnreadPost)
postList.AddOrder(lastUnreadPost.Id)
postList.SortByCreateAt()
return postList, nil
}
func (a *App) DeletePost(postId, deleteByID string) (*model.Post, *model.AppError) {
post, err := a.Srv.Store.Post().GetSingle(postId)
if err != nil {