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

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

@@ -4,6 +4,7 @@
package sqlstore
import (
"database/sql"
"fmt"
"net/http"
"regexp"
@@ -334,7 +335,7 @@ func (s *SqlPostStore) InvalidateLastPostTimeCache(channelId string) {
func (s *SqlPostStore) GetEtag(channelId string, allowFromCache bool) string {
if allowFromCache {
if cacheItem, ok := s.lastPostTimeCache.Get(channelId); ok {
if cacheItem, ok := s.lastPostTimeCache.Get(channelId); ok && cacheItem.(int64) > 0 {
if s.metrics != nil {
s.metrics.IncrementMemCacheHitCounter("Last Post Time")
}
@@ -661,6 +662,78 @@ func (s *SqlPostStore) getPostsAround(channelId string, postId string, limit int
return list, nil
}
func (s *SqlPostStore) GetPostIdBeforeTime(channelId string, time int64) (string, *model.AppError) {
return s.getPostIdAroundTime(channelId, time, true)
}
func (s *SqlPostStore) GetPostIdAfterTime(channelId string, time int64) (string, *model.AppError) {
return s.getPostIdAroundTime(channelId, time, false)
}
func (s *SqlPostStore) getPostIdAroundTime(channelId string, time int64, before bool) (string, *model.AppError) {
var direction sq.Sqlizer
var sort string
if before {
direction = sq.Lt{"CreateAt": time}
sort = "DESC"
} else {
direction = sq.Gt{"CreateAt": time}
sort = "ASC"
}
query := s.getQueryBuilder().
Select("Id").
From("Posts").
Where(sq.And{
direction,
sq.Eq{"ChannelId": channelId},
sq.Eq{"DeleteAt": int(0)},
}).
OrderBy("CreateAt " + sort).
Limit(1)
queryString, args, err := query.ToSql()
if err != nil {
return "", model.NewAppError("SqlPostStore.getPostIdAroundTime", "store.sql_post.get_post_id_around.app_error", nil, err.Error(), http.StatusInternalServerError)
}
var postId string
if err := s.GetMaster().SelectOne(&postId, queryString, args...); err != nil {
if err != sql.ErrNoRows {
return "", model.NewAppError("SqlPostStore.getPostIdAroundTime", "store.sql_post.get_post_id_around.app_error", nil, "channelId="+channelId+err.Error(), http.StatusInternalServerError)
}
}
return postId, nil
}
func (s *SqlPostStore) GetPostAfterTime(channelId string, time int64) (*model.Post, *model.AppError) {
query := s.getQueryBuilder().
Select("*").
From("Posts").
Where(sq.And{
sq.Gt{"CreateAt": time},
sq.Eq{"ChannelId": channelId},
sq.Eq{"DeleteAt": int(0)},
}).
OrderBy("CreateAt ASC").
Limit(1)
queryString, args, err := query.ToSql()
if err != nil {
return nil, model.NewAppError("SqlPostStore.GetPostAfterTime", "store.sql_post.get_post_after_time.app_error", nil, err.Error(), http.StatusInternalServerError)
}
var post *model.Post
if err := s.GetMaster().SelectOne(&post, queryString, args...); err != nil {
if err != sql.ErrNoRows {
return nil, model.NewAppError("SqlPostStore.GetPostAfterTime", "store.sql_post.get_post_after_time.app_error", nil, "channelId="+channelId+err.Error(), http.StatusInternalServerError)
}
}
return post, nil
}
func (s *SqlPostStore) getRootPosts(channelId string, offset int, limit int) store.StoreChannel {
return store.Do(func(result *store.StoreResult) {
var posts []*model.Post