Add top DMs route and handlers
Этот коммит содержится в:
@@ -6007,6 +6007,24 @@ func (s *OpenTracingLayerPostStore) GetSingle(id string, inclDeleted bool) (*mod
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (s *OpenTracingLayerPostStore) GetTopDMsForUserSince(userID string, since int64, offset int, limit int) (*model.TopDMList, error) {
|
||||
origCtx := s.Root.Store.Context()
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "PostStore.GetTopDMsForUserSince")
|
||||
s.Root.Store.SetContext(newCtx)
|
||||
defer func() {
|
||||
s.Root.Store.SetContext(origCtx)
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
result, err := s.PostStore.GetTopDMsForUserSince(userID, since, offset, limit)
|
||||
if err != nil {
|
||||
span.LogFields(spanlog.Error(err))
|
||||
ext.Error.Set(span, true)
|
||||
}
|
||||
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (s *OpenTracingLayerPostStore) HasAutoResponsePostByUserSince(options model.GetPostsSinceOptions, userId string) (bool, error) {
|
||||
origCtx := s.Root.Store.Context()
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "PostStore.HasAutoResponsePostByUserSince")
|
||||
|
||||
@@ -6806,6 +6806,27 @@ func (s *RetryLayerPostStore) GetSingle(id string, inclDeleted bool) (*model.Pos
|
||||
|
||||
}
|
||||
|
||||
func (s *RetryLayerPostStore) GetTopDMsForUserSince(userID string, since int64, offset int, limit int) (*model.TopDMList, error) {
|
||||
|
||||
tries := 0
|
||||
for {
|
||||
result, err := s.PostStore.GetTopDMsForUserSince(userID, since, offset, limit)
|
||||
if err == nil {
|
||||
return result, nil
|
||||
}
|
||||
if !isRepeatableError(err) {
|
||||
return result, err
|
||||
}
|
||||
tries++
|
||||
if tries >= 3 {
|
||||
err = errors.Wrap(err, "giving up after 3 consecutive repeatable transaction failures")
|
||||
return result, err
|
||||
}
|
||||
timepkg.Sleep(100 * timepkg.Millisecond)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (s *RetryLayerPostStore) HasAutoResponsePostByUserSince(options model.GetPostsSinceOptions, userId string) (bool, error) {
|
||||
|
||||
tries := 0
|
||||
|
||||
@@ -2963,3 +2963,55 @@ func (s *SqlPostStore) updateThreadsFromPosts(transaction *sqlxTxWrapper, posts
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SqlPostStore) GetTopDMsForUserSince(userID string, since int64, offset int, limit int) (*model.TopDMList, error) {
|
||||
channelSelector := s.getQueryBuilder().Select("Id", "TotalMsgCount").From("Channels").Join("ChannelMembers as cm on cm.ChannelId = Channels.Id").
|
||||
Where(sq.And{
|
||||
sq.Expr("Channels.Type = 'D'"),
|
||||
sq.Eq{"cm.UserId": userID},
|
||||
})
|
||||
var aggregator string
|
||||
|
||||
if s.DriverName() == model.DatabaseDriverMysql {
|
||||
aggregator = "group_concat(distinct cm.UserId) as Participants"
|
||||
} else {
|
||||
aggregator = "string_agg(distinct cm.UserId, ',') as Participants"
|
||||
}
|
||||
|
||||
topDMsBuilder := s.getQueryBuilder().Select("count(p.id) as MessageCount", aggregator).FromSelect(channelSelector, "vch").
|
||||
Join("ChannelMembers as cm on cm.ChannelId = vch.Id").
|
||||
Join("Posts as p on p.ChannelId = vch.Id").
|
||||
Where(sq.Gt{
|
||||
"p.UpdateAt": since,
|
||||
}).GroupBy("vch.id").
|
||||
Limit(uint64(limit)).
|
||||
Offset(uint64(offset))
|
||||
|
||||
topDMsBuilder = topDMsBuilder.OrderBy("MessageCount DESC").Limit(uint64(limit)).Offset(uint64(offset))
|
||||
|
||||
topDMs := make([]*model.TopDM, 0)
|
||||
sql, args, err := topDMsBuilder.ToSql()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "GetTopDMsForUserSince_ToSql")
|
||||
}
|
||||
err = s.GetReplicaX().Select(&topDMs, sql, args...)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to find top DMs for user-id: %s", userID)
|
||||
}
|
||||
|
||||
// fill SecondParticipant column
|
||||
topDMs = postProcessTopDMs(userID, topDMs)
|
||||
return model.GetTopDMListWithPagination(topDMs, limit), nil
|
||||
}
|
||||
|
||||
func postProcessTopDMs(userID string, topDMs []*model.TopDM) []*model.TopDM {
|
||||
for _, topDM := range topDMs {
|
||||
participants := strings.Split(topDM.Participants, ",")
|
||||
if participants[0] == userID {
|
||||
topDM.SecondParticipant = participants[1]
|
||||
} else {
|
||||
topDM.SecondParticipant = participants[0]
|
||||
}
|
||||
}
|
||||
return topDMs
|
||||
}
|
||||
|
||||
@@ -388,6 +388,9 @@ type PostStore interface {
|
||||
GetPostsSinceForSync(options model.GetPostsSinceForSyncOptions, cursor model.GetPostsSinceForSyncCursor, limit int) ([]*model.Post, model.GetPostsSinceForSyncCursor, error)
|
||||
// GetNthRecentPostTime returns the CreateAt time of the nth most recent post.
|
||||
GetNthRecentPostTime(n int64) (int64, error)
|
||||
|
||||
// Insights - top DMs
|
||||
GetTopDMsForUserSince(userID string, since int64, offset int, limit int) (*model.TopDMList, error)
|
||||
}
|
||||
|
||||
type UserStore interface {
|
||||
|
||||
@@ -700,6 +700,29 @@ func (_m *PostStore) GetSingle(id string, inclDeleted bool) (*model.Post, error)
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetTopDMsForUserSince provides a mock function with given fields: userID, since, offset, limit
|
||||
func (_m *PostStore) GetTopDMsForUserSince(userID string, since int64, offset int, limit int) (*model.TopDMList, error) {
|
||||
ret := _m.Called(userID, since, offset, limit)
|
||||
|
||||
var r0 *model.TopDMList
|
||||
if rf, ok := ret.Get(0).(func(string, int64, int, int) *model.TopDMList); ok {
|
||||
r0 = rf(userID, since, offset, limit)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*model.TopDMList)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(string, int64, int, int) error); ok {
|
||||
r1 = rf(userID, since, offset, limit)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// HasAutoResponsePostByUserSince provides a mock function with given fields: options, userId
|
||||
func (_m *PostStore) HasAutoResponsePostByUserSince(options model.GetPostsSinceOptions, userId string) (bool, error) {
|
||||
ret := _m.Called(options, userId)
|
||||
|
||||
@@ -5434,6 +5434,22 @@ func (s *TimerLayerPostStore) GetSingle(id string, inclDeleted bool) (*model.Pos
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (s *TimerLayerPostStore) GetTopDMsForUserSince(userID string, since int64, offset int, limit int) (*model.TopDMList, error) {
|
||||
start := time.Now()
|
||||
|
||||
result, err := s.PostStore.GetTopDMsForUserSince(userID, since, offset, limit)
|
||||
|
||||
elapsed := float64(time.Since(start)) / float64(time.Second)
|
||||
if s.Root.Metrics != nil {
|
||||
success := "false"
|
||||
if err == nil {
|
||||
success = "true"
|
||||
}
|
||||
s.Root.Metrics.ObserveStoreMethodDuration("PostStore.GetTopDMsForUserSince", success, elapsed)
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (s *TimerLayerPostStore) HasAutoResponsePostByUserSince(options model.GetPostsSinceOptions, userId string) (bool, error) {
|
||||
start := time.Now()
|
||||
|
||||
|
||||
Ссылка в новой задаче
Block a user