We add the necessary store methods to use GraphQL

```release-note
NONE
```
Этот коммит содержится в:
Agniva De Sarker
2022-02-02 22:44:22 +05:30
коммит произвёл GitHub
родитель e9a777f4e2
Коммит a733fb840d
23 изменённых файлов: 1037 добавлений и 59 удалений

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

@@ -885,7 +885,10 @@ func getChannelsForTeamForUser(c *Context, w http.ResponseWriter, r *http.Reques
return
}
channels, err := c.App.GetChannelsForTeamForUser(c.Params.TeamId, c.Params.UserId, c.Params.IncludeDeleted, lastDeleteAt)
channels, err := c.App.GetChannelsForTeamForUser(c.Params.TeamId, c.Params.UserId, &model.ChannelSearchOpts{
IncludeDeleted: c.Params.IncludeDeleted,
LastDeleteAt: lastDeleteAt,
})
if err != nil {
c.Err = err
return

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

@@ -210,7 +210,10 @@ func updateCategoriesForTeamForUser(c *Context, w http.ResponseWriter, r *http.R
}
func validateSidebarCategory(c *Context, teamId, userId string, category *model.SidebarCategoryWithChannels) *model.AppError {
channels, err := c.App.GetChannelsForTeamForUser(teamId, userId, true, 0)
channels, err := c.App.GetChannelsForTeamForUser(teamId, userId, &model.ChannelSearchOpts{
IncludeDeleted: true,
LastDeleteAt: 0,
})
if err != nil {
return model.NewAppError("validateSidebarCategory", "api.invalid_channel", nil, err.Error(), http.StatusBadRequest)
}
@@ -221,7 +224,10 @@ func validateSidebarCategory(c *Context, teamId, userId string, category *model.
}
func validateSidebarCategories(c *Context, teamId, userId string, categories []*model.SidebarCategoryWithChannels) *model.AppError {
channels, err := c.App.GetChannelsForTeamForUser(teamId, userId, true, 0)
channels, err := c.App.GetChannelsForTeamForUser(teamId, userId, &model.ChannelSearchOpts{
IncludeDeleted: true,
LastDeleteAt: 0,
})
if err != nil {
return model.NewAppError("validateSidebarCategory", "api.invalid_channel", nil, err.Error(), http.StatusBadRequest)
}

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

@@ -573,7 +573,8 @@ type AppIface interface {
GetChannelsForRetentionPolicy(policyID string, offset, limit int) (*model.ChannelsWithCount, *model.AppError)
GetChannelsForScheme(scheme *model.Scheme, offset int, limit int) (model.ChannelList, *model.AppError)
GetChannelsForSchemePage(scheme *model.Scheme, page int, perPage int) (model.ChannelList, *model.AppError)
GetChannelsForTeamForUser(teamID string, userID string, includeDeleted bool, lastDeleteAt int) (model.ChannelList, *model.AppError)
GetChannelsForTeamForUser(teamID string, userID string, opts *model.ChannelSearchOpts) (model.ChannelList, *model.AppError)
GetChannelsForTeamForUserWithCursor(teamID string, userID string, opts *model.ChannelSearchOpts, afterChannelID string) (model.ChannelList, *model.AppError)
GetChannelsForUser(userID string, includeDeleted bool, lastDeleteAt, pageSize int, fromChannelID string) (model.ChannelList, *model.AppError)
GetChannelsUserNotIn(teamID string, userID string, offset int, limit int) (model.ChannelList, *model.AppError)
GetCloudSession(token string) (*model.Session, *model.AppError)

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

@@ -1767,8 +1767,23 @@ func (a *App) GetChannelByNameForTeamName(channelName, teamName string, includeD
return result, nil
}
func (a *App) GetChannelsForTeamForUser(teamID string, userID string, includeDeleted bool, lastDeleteAt int) (model.ChannelList, *model.AppError) {
list, err := a.Srv().Store.Channel().GetChannels(teamID, userID, includeDeleted, lastDeleteAt)
func (a *App) GetChannelsForTeamForUser(teamID string, userID string, opts *model.ChannelSearchOpts) (model.ChannelList, *model.AppError) {
list, err := a.Srv().Store.Channel().GetChannels(teamID, userID, opts)
if err != nil {
var nfErr *store.ErrNotFound
switch {
case errors.As(err, &nfErr):
return nil, model.NewAppError("GetChannelsForUser", "app.channel.get_channels.not_found.app_error", nil, nfErr.Error(), http.StatusNotFound)
default:
return nil, model.NewAppError("GetChannelsForUser", "app.channel.get_channels.get.app_error", nil, err.Error(), http.StatusInternalServerError)
}
}
return list, nil
}
func (a *App) GetChannelsForTeamForUserWithCursor(teamID string, userID string, opts *model.ChannelSearchOpts, afterChannelID string) (model.ChannelList, *model.AppError) {
list, err := a.Srv().Store.Channel().GetChannelsWithCursor(teamID, userID, opts, afterChannelID)
if err != nil {
var nfErr *store.ErrNotFound
switch {

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

@@ -997,19 +997,28 @@ func TestGetChannelsForUser(t *testing.T) {
defer th.App.PermanentDeleteChannel(channel)
defer th.TearDown()
channelList, err := th.App.GetChannelsForTeamForUser(th.BasicTeam.Id, th.BasicUser.Id, false, 0)
channelList, err := th.App.GetChannelsForTeamForUser(th.BasicTeam.Id, th.BasicUser.Id, &model.ChannelSearchOpts{
IncludeDeleted: false,
LastDeleteAt: 0,
})
require.Nil(t, err)
require.Len(t, channelList, 4)
th.App.DeleteChannel(th.Context, channel, th.BasicUser.Id)
// Now we get all the non-archived channels for the user
channelList, err = th.App.GetChannelsForTeamForUser(th.BasicTeam.Id, th.BasicUser.Id, false, 0)
channelList, err = th.App.GetChannelsForTeamForUser(th.BasicTeam.Id, th.BasicUser.Id, &model.ChannelSearchOpts{
IncludeDeleted: false,
LastDeleteAt: 0,
})
require.Nil(t, err)
require.Len(t, channelList, 3)
// Now we get all the channels, even though are archived, for the user
channelList, err = th.App.GetChannelsForTeamForUser(th.BasicTeam.Id, th.BasicUser.Id, true, 0)
channelList, err = th.App.GetChannelsForTeamForUser(th.BasicTeam.Id, th.BasicUser.Id, &model.ChannelSearchOpts{
IncludeDeleted: true,
LastDeleteAt: 0,
})
require.Nil(t, err)
require.Len(t, channelList, 4)
}

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

@@ -5203,7 +5203,7 @@ func (a *OpenTracingAppLayer) GetChannelsForSchemePage(scheme *model.Scheme, pag
return resultVar0, resultVar1
}
func (a *OpenTracingAppLayer) GetChannelsForTeamForUser(teamID string, userID string, includeDeleted bool, lastDeleteAt int) (model.ChannelList, *model.AppError) {
func (a *OpenTracingAppLayer) GetChannelsForTeamForUser(teamID string, userID string, opts *model.ChannelSearchOpts) (model.ChannelList, *model.AppError) {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetChannelsForTeamForUser")
@@ -5215,7 +5215,29 @@ func (a *OpenTracingAppLayer) GetChannelsForTeamForUser(teamID string, userID st
}()
defer span.Finish()
resultVar0, resultVar1 := a.app.GetChannelsForTeamForUser(teamID, userID, includeDeleted, lastDeleteAt)
resultVar0, resultVar1 := a.app.GetChannelsForTeamForUser(teamID, userID, opts)
if resultVar1 != nil {
span.LogFields(spanlog.Error(resultVar1))
ext.Error.Set(span, true)
}
return resultVar0, resultVar1
}
func (a *OpenTracingAppLayer) GetChannelsForTeamForUserWithCursor(teamID string, userID string, opts *model.ChannelSearchOpts, afterChannelID string) (model.ChannelList, *model.AppError) {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetChannelsForTeamForUserWithCursor")
a.ctx = newCtx
a.app.Srv().Store.SetContext(newCtx)
defer func() {
a.app.Srv().Store.SetContext(origCtx)
a.ctx = origCtx
}()
defer span.Finish()
resultVar0, resultVar1 := a.app.GetChannelsForTeamForUserWithCursor(teamID, userID, opts, afterChannelID)
if resultVar1 != nil {
span.LogFields(spanlog.Error(resultVar1))

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

@@ -437,7 +437,10 @@ func (api *PluginAPI) GetChannelByNameForTeamName(teamName, channelName string,
}
func (api *PluginAPI) GetChannelsForTeamForUser(teamID, userID string, includeDeleted bool) ([]*model.Channel, *model.AppError) {
channels, err := api.app.GetChannelsForTeamForUser(teamID, userID, includeDeleted, 0)
channels, err := api.app.GetChannelsForTeamForUser(teamID, userID, &model.ChannelSearchOpts{
IncludeDeleted: includeDeleted,
LastDeleteAt: 0,
})
if err != nil {
return nil, err
}

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

@@ -1116,7 +1116,10 @@ func (a *App) LeaveTeam(c *request.Context, team *model.Team, user *model.User,
var channelList model.ChannelList
var nErr error
if channelList, nErr = a.Srv().Store.Channel().GetChannels(team.Id, user.Id, true, 0); nErr != nil {
if channelList, nErr = a.Srv().Store.Channel().GetChannels(team.Id, user.Id, &model.ChannelSearchOpts{
IncludeDeleted: true,
LastDeleteAt: 0,
}); nErr != nil {
var nfErr *store.ErrNotFound
if errors.As(nErr, &nfErr) {
channelList = model.ChannelList{}

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

@@ -868,7 +868,10 @@ func (a *App) invalidateUserChannelMembersCaches(userID string) *model.AppError
}
for _, team := range teamsForUser {
channelsForUser, err := a.GetChannelsForTeamForUser(team.Id, userID, false, 0)
channelsForUser, err := a.GetChannelsForTeamForUser(team.Id, userID, &model.ChannelSearchOpts{
IncludeDeleted: false,
LastDeleteAt: 0,
})
if err != nil {
return err
}

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

@@ -178,7 +178,10 @@ func manualTest(c *web.Context, w http.ResponseWriter, r *http.Request) {
func getChannelID(a app.AppIface, channelname string, teamid string, userid string) (string, bool) {
// Grab all the channels
channels, err := a.Srv().Store.Channel().GetChannels(teamid, userid, false, 0)
channels, err := a.Srv().Store.Channel().GetChannels(teamid, userid, &model.ChannelSearchOpts{
IncludeDeleted: false,
LastDeleteAt: 0,
})
if err != nil {
mlog.Debug("Unable to get channels")
return "", false

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

@@ -141,6 +141,8 @@ type ChannelSearchOpts struct {
Private bool
Page *int
PerPage *int
LastDeleteAt int
LastUpdateAt int
}
type ChannelMemberCountByGroup struct {

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

@@ -1087,7 +1087,7 @@ func (s *OpenTracingLayerChannelStore) GetChannelUnread(channelID string, userID
return result, err
}
func (s *OpenTracingLayerChannelStore) GetChannels(teamID string, userID string, includeDeleted bool, lastDeleteAt int) (model.ChannelList, error) {
func (s *OpenTracingLayerChannelStore) GetChannels(teamID string, userID string, opts *model.ChannelSearchOpts) (model.ChannelList, error) {
origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.GetChannels")
s.Root.Store.SetContext(newCtx)
@@ -1096,7 +1096,7 @@ func (s *OpenTracingLayerChannelStore) GetChannels(teamID string, userID string,
}()
defer span.Finish()
result, err := s.ChannelStore.GetChannels(teamID, userID, includeDeleted, lastDeleteAt)
result, err := s.ChannelStore.GetChannels(teamID, userID, opts)
if err != nil {
span.LogFields(spanlog.Error(err))
ext.Error.Set(span, true)
@@ -1177,6 +1177,24 @@ func (s *OpenTracingLayerChannelStore) GetChannelsByUser(userID string, includeD
return result, err
}
func (s *OpenTracingLayerChannelStore) GetChannelsWithCursor(teamId string, userId string, opts *model.ChannelSearchOpts, afterChannelID string) (model.ChannelList, error) {
origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.GetChannelsWithCursor")
s.Root.Store.SetContext(newCtx)
defer func() {
s.Root.Store.SetContext(origCtx)
}()
defer span.Finish()
result, err := s.ChannelStore.GetChannelsWithCursor(teamId, userId, opts, afterChannelID)
if err != nil {
span.LogFields(spanlog.Error(err))
ext.Error.Set(span, true)
}
return result, err
}
func (s *OpenTracingLayerChannelStore) GetChannelsWithTeamDataByIds(channelIds []string, includeDeleted bool) ([]*model.ChannelWithTeamData, error) {
origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.GetChannelsWithTeamDataByIds")
@@ -1442,6 +1460,24 @@ func (s *OpenTracingLayerChannelStore) GetMembersForUser(teamID string, userID s
return result, err
}
func (s *OpenTracingLayerChannelStore) GetMembersForUserWithCursor(userID string, afterChannel string, afterUser string, limit int, lastUpdateAt int) (model.ChannelMembers, error) {
origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.GetMembersForUserWithCursor")
s.Root.Store.SetContext(newCtx)
defer func() {
s.Root.Store.SetContext(origCtx)
}()
defer span.Finish()
result, err := s.ChannelStore.GetMembersForUserWithCursor(userID, afterChannel, afterUser, limit, lastUpdateAt)
if err != nil {
span.LogFields(spanlog.Error(err))
ext.Error.Set(span, true)
}
return result, err
}
func (s *OpenTracingLayerChannelStore) GetMembersForUserWithPagination(userID string, page int, perPage int) (model.ChannelMembersWithTeamData, error) {
origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.GetMembersForUserWithPagination")
@@ -1460,6 +1496,24 @@ func (s *OpenTracingLayerChannelStore) GetMembersForUserWithPagination(userID st
return result, err
}
func (s *OpenTracingLayerChannelStore) GetMembersInfoByChannelIds(channelIDs []string) (map[string][]*model.User, error) {
origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.GetMembersInfoByChannelIds")
s.Root.Store.SetContext(newCtx)
defer func() {
s.Root.Store.SetContext(origCtx)
}()
defer span.Finish()
result, err := s.ChannelStore.GetMembersInfoByChannelIds(channelIDs)
if err != nil {
span.LogFields(spanlog.Error(err))
ext.Error.Set(span, true)
}
return result, err
}
func (s *OpenTracingLayerChannelStore) GetMoreChannels(teamID string, userID string, offset int, limit int) (model.ChannelList, error) {
origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.GetMoreChannels")
@@ -2446,6 +2500,24 @@ func (s *OpenTracingLayerChannelMemberHistoryStore) DeleteOrphanedRows(limit int
return result, err
}
func (s *OpenTracingLayerChannelMemberHistoryStore) GetChannelsLeftSince(userID string, since int64) ([]string, error) {
origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelMemberHistoryStore.GetChannelsLeftSince")
s.Root.Store.SetContext(newCtx)
defer func() {
s.Root.Store.SetContext(origCtx)
}()
defer span.Finish()
result, err := s.ChannelMemberHistoryStore.GetChannelsLeftSince(userID, since)
if err != nil {
span.LogFields(spanlog.Error(err))
ext.Error.Set(span, true)
}
return result, err
}
func (s *OpenTracingLayerChannelMemberHistoryStore) GetUsersInChannelDuring(startTime int64, endTime int64, channelID string) ([]*model.ChannelMemberHistoryResult, error) {
origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelMemberHistoryStore.GetUsersInChannelDuring")

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

@@ -1213,11 +1213,11 @@ func (s *RetryLayerChannelStore) GetChannelUnread(channelID string, userID strin
}
func (s *RetryLayerChannelStore) GetChannels(teamID string, userID string, includeDeleted bool, lastDeleteAt int) (model.ChannelList, error) {
func (s *RetryLayerChannelStore) GetChannels(teamID string, userID string, opts *model.ChannelSearchOpts) (model.ChannelList, error) {
tries := 0
for {
result, err := s.ChannelStore.GetChannels(teamID, userID, includeDeleted, lastDeleteAt)
result, err := s.ChannelStore.GetChannels(teamID, userID, opts)
if err == nil {
return result, nil
}
@@ -1318,6 +1318,27 @@ func (s *RetryLayerChannelStore) GetChannelsByUser(userID string, includeDeleted
}
func (s *RetryLayerChannelStore) GetChannelsWithCursor(teamId string, userId string, opts *model.ChannelSearchOpts, afterChannelID string) (model.ChannelList, error) {
tries := 0
for {
result, err := s.ChannelStore.GetChannelsWithCursor(teamId, userId, opts, afterChannelID)
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 *RetryLayerChannelStore) GetChannelsWithTeamDataByIds(channelIds []string, includeDeleted bool) ([]*model.ChannelWithTeamData, error) {
tries := 0
@@ -1618,6 +1639,27 @@ func (s *RetryLayerChannelStore) GetMembersForUser(teamID string, userID string)
}
func (s *RetryLayerChannelStore) GetMembersForUserWithCursor(userID string, afterChannel string, afterUser string, limit int, lastUpdateAt int) (model.ChannelMembers, error) {
tries := 0
for {
result, err := s.ChannelStore.GetMembersForUserWithCursor(userID, afterChannel, afterUser, limit, lastUpdateAt)
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 *RetryLayerChannelStore) GetMembersForUserWithPagination(userID string, page int, perPage int) (model.ChannelMembersWithTeamData, error) {
tries := 0
@@ -1639,6 +1681,27 @@ func (s *RetryLayerChannelStore) GetMembersForUserWithPagination(userID string,
}
func (s *RetryLayerChannelStore) GetMembersInfoByChannelIds(channelIDs []string) (map[string][]*model.User, error) {
tries := 0
for {
result, err := s.ChannelStore.GetMembersInfoByChannelIds(channelIDs)
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 *RetryLayerChannelStore) GetMoreChannels(teamID string, userID string, offset int, limit int) (model.ChannelList, error) {
tries := 0
@@ -2716,6 +2779,27 @@ func (s *RetryLayerChannelMemberHistoryStore) DeleteOrphanedRows(limit int) (int
}
func (s *RetryLayerChannelMemberHistoryStore) GetChannelsLeftSince(userID string, since int64) ([]string, error) {
tries := 0
for {
result, err := s.ChannelMemberHistoryStore.GetChannelsLeftSince(userID, since)
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 *RetryLayerChannelMemberHistoryStore) GetUsersInChannelDuring(startTime int64, endTime int64, channelID string) ([]*model.ChannelMemberHistoryResult, error) {
tries := 0

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

@@ -160,7 +160,10 @@ func (s SearchFileInfoStore) PermanentDeleteByUser(userId string) (int64, error)
func (s SearchFileInfoStore) Search(paramsList []*model.SearchParams, userId, teamId string, page, perPage int) (*model.FileInfoList, error) {
for _, engine := range s.rootStore.searchEngine.GetActiveEngines() {
if engine.IsSearchEnabled() {
userChannels, nErr := s.rootStore.Channel().GetChannels(teamId, userId, paramsList[0].IncludeDeletedChannels, 0)
userChannels, nErr := s.rootStore.Channel().GetChannels(teamId, userId, &model.ChannelSearchOpts{
IncludeDeleted: paramsList[0].IncludeDeletedChannels,
LastDeleteAt: 0,
})
if nErr != nil {
return nil, nErr
}

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

@@ -142,7 +142,11 @@ func (s SearchPostStore) searchPostsForUserByEngine(engine searchengine.SearchEn
}
// We only allow the user to search in channels they are a member of.
userChannels, err2 := s.rootStore.Channel().GetChannels(teamId, userId, paramsList[0].IncludeDeletedChannels, 0)
userChannels, err2 := s.rootStore.Channel().GetChannels(teamId, userId,
&model.ChannelSearchOpts{
IncludeDeleted: paramsList[0].IncludeDeletedChannels,
LastDeleteAt: 0,
})
if err2 != nil {
return nil, errors.Wrap(err2, "error getting channel for user")
}

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

@@ -255,3 +255,24 @@ func (s SqlChannelMemberHistoryStore) PermanentDeleteBatch(endTime int64, limit
}
return rowsAffected, nil
}
// GetChannelsLeftSince returns list of channels that the user has left after a given time,
// but has not rejoined again.
func (s SqlChannelMemberHistoryStore) GetChannelsLeftSince(userID string, since int64) ([]string, error) {
query, params, err := s.getQueryBuilder().
Select("ChannelId").
From("ChannelMemberHistory").
GroupBy("ChannelId").
Where(sq.Eq{"UserId": userID}).
Having("MAX(LeaveTime) > MAX(JoinTime) AND MAX(LeaveTime) IS NOT NULL AND MAX(LeaveTime) >= ?", since).ToSql()
if err != nil {
return nil, errors.Wrap(err, "channel_member_history_to_sql")
}
channelIds := []string{}
err = s.GetReplicaX().Select(&channelIds, query, params...)
if err != nil {
return nil, errors.Wrapf(err, "GetChannelsLeftSince userId=%s since=%d", userID, since)
}
return channelIds, nil
}

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

@@ -1084,37 +1084,105 @@ func (s SqlChannelStore) PermanentDeleteMembersByChannel(channelId string) error
return nil
}
func (s SqlChannelStore) GetChannels(teamId string, userId string, includeDeleted bool, lastDeleteAt int) (model.ChannelList, error) {
func (s SqlChannelStore) GetChannels(teamId string, userId string, opts *model.ChannelSearchOpts) (model.ChannelList, error) {
query := s.getQueryBuilder().
Select("Channels.*").
From("Channels, ChannelMembers").
Select("ch.*").
From("Channels ch, ChannelMembers cm").
Where(
sq.And{
sq.Expr("Id = ChannelId"),
sq.Eq{"UserId": userId},
sq.Expr("ch.Id = cm.ChannelId"),
sq.Eq{"cm.UserId": userId},
},
).
OrderBy("DisplayName")
OrderBy("ch.DisplayName")
if teamId != "" {
query = query.Where(sq.Or{
sq.Eq{"TeamId": teamId},
sq.Eq{"TeamId": ""},
sq.Eq{"ch.TeamId": teamId},
sq.Eq{"ch.TeamId": ""},
})
}
if includeDeleted {
if lastDeleteAt != 0 {
if opts.IncludeDeleted {
if opts.LastDeleteAt != 0 {
// We filter by non-archived, and archived >= a timestamp.
query = query.Where(sq.Or{
sq.Eq{"DeleteAt": 0},
sq.GtOrEq{"DeleteAt": lastDeleteAt},
sq.Eq{"ch.DeleteAt": 0},
sq.GtOrEq{"ch.DeleteAt": opts.LastDeleteAt},
})
}
// If lastDeleteAt is not set, we include everything. That means no filter is needed.
// If opts.LastDeleteAt is not set, we include everything. That means no filter is needed.
} else {
// Don't include archived channels.
query = query.Where(sq.Eq{"DeleteAt": 0})
query = query.Where(sq.Eq{"ch.DeleteAt": 0})
}
if opts.LastUpdateAt > 0 {
query = query.Where(sq.GtOrEq{"ch.UpdateAt": opts.LastUpdateAt})
}
channels := model.ChannelList{}
sql, args, err := query.ToSql()
if err != nil {
return nil, errors.Wrapf(err, "getchannels_tosql")
}
err = s.GetReplicaX().Select(&channels, sql, args...)
if err != nil {
return nil, errors.Wrapf(err, "failed to get channels with TeamId=%s and UserId=%s", teamId, userId)
}
if len(channels) == 0 {
return nil, store.NewErrNotFound("Channel", "userId="+userId)
}
return channels, nil
}
func (s SqlChannelStore) GetChannelsWithCursor(teamId string, userId string, opts *model.ChannelSearchOpts, afterChannelID string) (model.ChannelList, error) {
query := s.getQueryBuilder().
Select("ch.*").
From("Channels ch, ChannelMembers cm").
Where(
sq.And{
sq.Expr("ch.Id = cm.ChannelId"),
sq.Eq{"cm.UserId": userId},
},
).
OrderBy("ch.Id")
if opts.PerPage != nil {
// The limit is verified at the GraphQL layer.
query = query.Limit(uint64(*opts.PerPage))
}
if afterChannelID != "" {
query = query.Where(sq.Gt{"ch.Id": afterChannelID})
}
if teamId != "" {
query = query.Where(sq.Or{
sq.Eq{"ch.TeamId": teamId},
sq.Eq{"ch.TeamId": ""},
})
}
if opts.IncludeDeleted {
if opts.LastDeleteAt != 0 {
// We filter by non-archived, and archived >= a timestamp.
query = query.Where(sq.Or{
sq.Eq{"ch.DeleteAt": 0},
sq.GtOrEq{"ch.DeleteAt": opts.LastDeleteAt},
})
}
// If opts.LastDeleteAt is not set, we include everything. That means no filter is needed.
} else {
// Don't include archived channels.
query = query.Where(sq.Eq{"ch.DeleteAt": 0})
}
if opts.LastUpdateAt > 0 {
query = query.Where(sq.GtOrEq{"ch.UpdateAt": opts.LastUpdateAt})
}
channels := model.ChannelList{}
@@ -2773,6 +2841,56 @@ func (s SqlChannelStore) GetMembersForUser(teamId string, userId string) (model.
return dbMembers.ToModel(), nil
}
func (s SqlChannelStore) GetMembersForUserWithCursor(userID, afterChannel, afterUser string, limit, lastUpdateAt int) (model.ChannelMembers, error) {
query := s.getQueryBuilder().
Select("ChannelMembers.*",
"TeamScheme.DefaultChannelGuestRole TeamSchemeDefaultGuestRole",
"TeamScheme.DefaultChannelUserRole TeamSchemeDefaultUserRole",
"TeamScheme.DefaultChannelAdminRole TeamSchemeDefaultAdminRole",
"ChannelScheme.DefaultChannelGuestRole ChannelSchemeDefaultGuestRole",
"ChannelScheme.DefaultChannelUserRole ChannelSchemeDefaultUserRole",
"ChannelScheme.DefaultChannelAdminRole ChannelSchemeDefaultAdminRole").
From("ChannelMembers").
InnerJoin("Channels ON ChannelMembers.ChannelId = Channels.Id").
LeftJoin("Schemes ChannelScheme ON Channels.SchemeId = ChannelScheme.Id").
LeftJoin("Teams ON Channels.TeamId = Teams.Id").
LeftJoin("Schemes TeamScheme ON Teams.SchemeId = TeamScheme.Id").
Where(sq.Eq{
"ChannelMembers.UserId": userID,
"Channels.DeleteAt": 0,
}).
OrderBy("ChannelId, UserId ASC").
// The limit is verified at the GraphQL layer.
Limit(uint64(limit))
if afterChannel != "" && afterUser != "" {
query = query.Where(sq.Or{
sq.Gt{"ChannelMembers.ChannelId": afterChannel},
sq.And{
sq.Eq{"ChannelMembers.ChannelId": afterChannel},
sq.Gt{"ChannelMembers.UserId": afterUser},
},
})
}
if lastUpdateAt != 0 {
query = query.Where(sq.GtOrEq{"ChannelMembers.LastUpdateAt": lastUpdateAt})
}
queryString, args, err := query.ToSql()
if err != nil {
return nil, errors.Wrap(err, "getMembersForUserWithCursor_tosql")
}
dbMembers := channelMemberWithSchemeRolesList{}
err = s.GetReplicaX().Select(&dbMembers, queryString, args...)
if err != nil {
return nil, errors.Wrapf(err, "failed to find ChannelMembers data with userId=%s", userID)
}
return dbMembers.ToModel(), nil
}
func (s SqlChannelStore) GetMembersForUserWithPagination(userId string, page, perPage int) (model.ChannelMembersWithTeamData, error) {
dbMembers := channelMemberWithTeamWithSchemeRolesList{}
offset := page * perPage
@@ -3470,6 +3588,43 @@ func (s SqlChannelStore) GetMembersByChannelIds(channelIds []string, userId stri
return dbMembers.ToModel(), nil
}
func (s SqlChannelStore) GetMembersInfoByChannelIds(channelIDs []string) (map[string][]*model.User, error) {
query := s.getQueryBuilder().
Select("Channels.Id as ChannelId, Users.Id, Users.FirstName, Users.LastName, Users.Nickname, Users.Username").
From("ChannelMembers as cm").
Join("Channels ON cm.ChannelId = Channels.Id").
Join("Users ON cm.UserId = Users.Id").
Where(sq.Eq{
"Channels.Id": channelIDs,
"Channels.DeleteAt": 0,
})
sql, args, err := query.ToSql()
if err != nil {
return nil, errors.Wrap(err, "dm_gm_names_tosql")
}
res := []*struct {
model.User
ChannelId string
}{}
if err := s.GetReplicaX().Select(&res, sql, args...); err != nil {
return nil, errors.Wrap(err, "failed to find channels display name")
}
if len(res) == 0 {
return nil, store.NewErrNotFound("User", fmt.Sprintf("%v", channelIDs))
}
userInfo := make(map[string][]*model.User)
for _, item := range res {
userInfo[item.ChannelId] = append(userInfo[item.ChannelId], &item.User)
}
return userInfo, nil
}
func (s SqlChannelStore) GetChannelsByScheme(schemeId string, offset int, limit int) (model.ChannelList, error) {
channels := model.ChannelList{}
err := s.GetReplicaX().Select(&channels, "SELECT * FROM Channels WHERE SchemeId = ? ORDER BY DisplayName LIMIT ? OFFSET ?", schemeId, limit, offset)

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

@@ -178,7 +178,8 @@ type ChannelStore interface {
GetByNameIncludeDeleted(team_id string, name string, allowFromCache bool) (*model.Channel, error)
GetDeletedByName(team_id string, name string) (*model.Channel, error)
GetDeleted(team_id string, offset int, limit int, userID string) (model.ChannelList, error)
GetChannels(teamID string, userID string, includeDeleted bool, lastDeleteAt int) (model.ChannelList, error)
GetChannels(teamID, userID string, opts *model.ChannelSearchOpts) (model.ChannelList, error)
GetChannelsWithCursor(teamId string, userId string, opts *model.ChannelSearchOpts, afterChannelID string) (model.ChannelList, error)
GetChannelsByUser(userID string, includeDeleted bool, lastDeleteAt, pageSize int, fromChannelID string) (model.ChannelList, error)
GetAllChannelMembersById(id string) ([]string, error)
GetAllChannels(page, perPage int, opts ChannelSearchOpts) (model.ChannelListWithTeamData, error)
@@ -230,6 +231,7 @@ type ChannelStore interface {
GetMembersForUser(teamID string, userID string) (model.ChannelMembers, error)
GetTeamMembersForChannel(channelID string) ([]string, error)
GetMembersForUserWithPagination(userID string, page, perPage int) (model.ChannelMembersWithTeamData, error)
GetMembersForUserWithCursor(userID, afterChannel, afterUser string, limit, lastUpdateAt int) (model.ChannelMembers, error)
Autocomplete(userID, term string, includeDeleted bool) (model.ChannelListWithTeamData, error)
AutocompleteInTeam(teamID, userID, term string, includeDeleted bool) (model.ChannelList, error)
AutocompleteInTeamForSearch(teamID string, userID string, term string, includeDeleted bool) (model.ChannelList, error)
@@ -241,6 +243,7 @@ type ChannelStore interface {
SearchGroupChannels(userID, term string) (model.ChannelList, error)
GetMembersByIds(channelID string, userIds []string) (model.ChannelMembers, error)
GetMembersByChannelIds(channelIds []string, userID string) (model.ChannelMembers, error)
GetMembersInfoByChannelIds(channelIDs []string) (map[string][]*model.User, error)
AnalyticsDeletedTypeCount(teamID string, channelType string) (int64, error)
GetChannelUnread(channelID, userID string) (*model.ChannelUnread, error)
ClearCaches()
@@ -284,6 +287,7 @@ type ChannelMemberHistoryStore interface {
PermanentDeleteBatchForRetentionPolicies(now, globalPolicyEndTime, limit int64, cursor model.RetentionPolicyCursor) (int64, model.RetentionPolicyCursor, error)
DeleteOrphanedRows(limit int) (deleted int64, err error)
PermanentDeleteBatch(endTime int64, limit int64) (int64, error)
GetChannelsLeftSince(userID string, since int64) ([]string, error)
}
type ThreadStore interface {
GetThreadFollowers(threadID string, fetchOnlyActive bool) ([]string, error)
@@ -919,6 +923,8 @@ type ChannelSearchOpts struct {
Private bool
Page *int
PerPage *int
LastDeleteAt int
LastUpdateAt int
}
func (c *ChannelSearchOpts) IsPaginated() bool {

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

@@ -22,6 +22,7 @@ func TestChannelMemberHistoryStore(t *testing.T, ss store.Store) {
t.Run("TestGetUsersInChannelAtChannelMembers", func(t *testing.T) { testGetUsersInChannelAtChannelMembers(t, ss) })
t.Run("TestPermanentDeleteBatch", func(t *testing.T) { testPermanentDeleteBatch(t, ss) })
t.Run("TestPermanentDeleteBatchForRetentionPolicies", func(t *testing.T) { testPermanentDeleteBatchForRetentionPolicies(t, ss) })
t.Run("TestGetChannelsLeftSince", func(t *testing.T) { testGetChannelsLeftSince(t, ss) })
}
func testLogJoinEvent(t *testing.T, ss store.Store) {
@@ -29,7 +30,7 @@ func testLogJoinEvent(t *testing.T, ss store.Store) {
ch := model.Channel{
TeamId: model.NewId(),
DisplayName: "Display " + model.NewId(),
Name: "zz" + model.NewId() + "b",
Name: NewTestId(),
Type: model.ChannelTypeOpen,
}
channel, err := ss.Channel().Save(&ch, -1)
@@ -55,7 +56,7 @@ func testLogLeaveEvent(t *testing.T, ss store.Store) {
ch := model.Channel{
TeamId: model.NewId(),
DisplayName: "Display " + model.NewId(),
Name: "zz" + model.NewId() + "b",
Name: NewTestId(),
Type: model.ChannelTypeOpen,
}
channel, err := ss.Channel().Save(&ch, -1)
@@ -84,7 +85,7 @@ func testGetUsersInChannelAtChannelMemberHistory(t *testing.T, ss store.Store) {
ch := &model.Channel{
TeamId: model.NewId(),
DisplayName: "Display " + model.NewId(),
Name: "zz" + model.NewId() + "b",
Name: NewTestId(),
Type: model.ChannelTypeOpen,
}
channel, err := ss.Channel().Save(ch, -1)
@@ -180,7 +181,7 @@ func testGetUsersInChannelAtChannelMembers(t *testing.T, ss store.Store) {
channel := &model.Channel{
TeamId: model.NewId(),
DisplayName: "Display " + model.NewId(),
Name: "zz" + model.NewId() + "b",
Name: NewTestId(),
Type: model.ChannelTypeOpen,
}
channel, err := ss.Channel().Save(channel, -1)
@@ -292,7 +293,7 @@ func testPermanentDeleteBatch(t *testing.T, ss store.Store) {
channel := &model.Channel{
TeamId: model.NewId(),
DisplayName: "Display " + model.NewId(),
Name: "zz" + model.NewId() + "b",
Name: NewTestId(),
Type: model.ChannelTypeOpen,
}
channel, err := ss.Channel().Save(channel, -1)
@@ -389,3 +390,54 @@ func testPermanentDeleteBatchForRetentionPolicies(t *testing.T, ss store.Store)
require.NoError(t, err)
require.Empty(t, result, "history should have been deleted by channel policy")
}
func testGetChannelsLeftSince(t *testing.T, ss store.Store) {
team, err := ss.Team().Save(&model.Team{
DisplayName: "DisplayName",
Name: "team" + model.NewId(),
Email: MakeEmail(),
Type: model.TeamOpen,
})
require.NoError(t, err)
channel, err := ss.Channel().Save(&model.Channel{
TeamId: team.Id,
DisplayName: "DisplayName",
Name: "channel" + model.NewId(),
Type: model.ChannelTypeOpen,
}, -1)
require.NoError(t, err)
userID := model.NewId()
joinTime := int64(1000)
err = ss.ChannelMemberHistory().LogJoinEvent(userID, channel.Id, joinTime)
require.NoError(t, err)
// has not left
ids, err := ss.ChannelMemberHistory().GetChannelsLeftSince(userID, joinTime)
require.NoError(t, err)
assert.Empty(t, ids)
// left
err = ss.ChannelMemberHistory().LogLeaveEvent(userID, channel.Id, joinTime+100)
require.NoError(t, err)
ids, err = ss.ChannelMemberHistory().GetChannelsLeftSince(userID, joinTime+100)
require.NoError(t, err)
assert.Equal(t, []string{channel.Id}, ids)
ids, err = ss.ChannelMemberHistory().GetChannelsLeftSince(userID, joinTime+200)
require.NoError(t, err)
assert.Empty(t, ids)
// joined and left again.
err = ss.ChannelMemberHistory().LogJoinEvent(userID, channel.Id, joinTime+200)
require.NoError(t, err)
err = ss.ChannelMemberHistory().LogLeaveEvent(userID, channel.Id, joinTime+300)
require.NoError(t, err)
// should be same for both time stamps
ids, err = ss.ChannelMemberHistory().GetChannelsLeftSince(userID, joinTime+100)
require.NoError(t, err)
assert.Equal(t, []string{channel.Id}, ids)
ids, err = ss.ChannelMemberHistory().GetChannelsLeftSince(userID, joinTime+300)
require.NoError(t, err)
assert.Equal(t, []string{channel.Id}, ids)
}

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

@@ -79,6 +79,7 @@ func TestChannelStore(t *testing.T, ss store.Store, s SqlStore) {
t.Run("RemoveMembers", func(t *testing.T) { testChannelRemoveMembers(t, ss) })
t.Run("ChannelDeleteMemberStore", func(t *testing.T) { testChannelDeleteMemberStore(t, ss) })
t.Run("GetChannels", func(t *testing.T) { testChannelStoreGetChannels(t, ss) })
t.Run("GetChannelsWithCursor", func(t *testing.T) { testChannelStoreGetChannelsWithCursor(t, ss) })
t.Run("GetChannelsByUser", func(t *testing.T) { testChannelStoreGetChannelsByUser(t, ss) })
t.Run("GetAllChannels", func(t *testing.T) { testChannelStoreGetAllChannels(t, ss, s) })
t.Run("GetMoreChannels", func(t *testing.T) { testChannelStoreGetMoreChannels(t, ss) })
@@ -87,6 +88,7 @@ func TestChannelStore(t *testing.T, ss store.Store, s SqlStore) {
t.Run("GetPublicChannelsByIdsForTeam", func(t *testing.T) { testChannelStoreGetPublicChannelsByIdsForTeam(t, ss) })
t.Run("GetChannelCounts", func(t *testing.T) { testChannelStoreGetChannelCounts(t, ss) })
t.Run("GetMembersForUser", func(t *testing.T) { testChannelStoreGetMembersForUser(t, ss) })
t.Run("GetMembersForUserWithCursor", func(t *testing.T) { testChannelStoreGetMembersForUserWithCursor(t, ss) })
t.Run("GetMembersForUserWithPagination", func(t *testing.T) { testChannelStoreGetMembersForUserWithPagination(t, ss) })
t.Run("CountPostsAfter", func(t *testing.T) { testCountPostsAfter(t, ss) })
t.Run("UpdateLastViewedAt", func(t *testing.T) { testChannelStoreUpdateLastViewedAt(t, ss) })
@@ -105,6 +107,7 @@ func TestChannelStore(t *testing.T, ss store.Store, s SqlStore) {
t.Run("SearchAllChannels", func(t *testing.T) { testChannelStoreSearchAllChannels(t, ss) })
t.Run("GetMembersByIds", func(t *testing.T) { testChannelStoreGetMembersByIds(t, ss) })
t.Run("GetMembersByChannelIds", func(t *testing.T) { testChannelStoreGetMembersByChannelIds(t, ss) })
t.Run("GetMembersInfoByChannelIds", func(t *testing.T) { testChannelStoreGetMembersInfoByChannelIds(t, ss) })
t.Run("SearchGroupChannels", func(t *testing.T) { testChannelStoreSearchGroupChannels(t, ss) })
t.Run("AnalyticsDeletedTypeCount", func(t *testing.T) { testChannelStoreAnalyticsDeletedTypeCount(t, ss) })
t.Run("GetPinnedPosts", func(t *testing.T) { testChannelStoreGetPinnedPosts(t, ss) })
@@ -719,7 +722,10 @@ func testChannelStoreDelete(t *testing.T, ss store.Store) {
nErr = ss.Channel().Delete(o3.Id, model.GetMillis())
require.NoError(t, nErr, nErr)
list, nErr := ss.Channel().GetChannels(o1.TeamId, m1.UserId, false, 0)
list, nErr := ss.Channel().GetChannels(o1.TeamId, m1.UserId, &model.ChannelSearchOpts{
IncludeDeleted: false,
LastDeleteAt: 0,
})
require.NoError(t, nErr)
require.Len(t, list, 1, "invalid number of channels")
@@ -730,7 +736,10 @@ func testChannelStoreDelete(t *testing.T, ss store.Store) {
cresult := ss.Channel().PermanentDelete(o2.Id)
require.NoError(t, cresult)
list, nErr = ss.Channel().GetChannels(o1.TeamId, m1.UserId, false, 0)
list, nErr = ss.Channel().GetChannels(o1.TeamId, m1.UserId, &model.ChannelSearchOpts{
IncludeDeleted: false,
LastDeleteAt: 0,
})
if assert.Error(t, nErr) {
var nfErr *store.ErrNotFound
require.True(t, errors.As(nErr, &nfErr))
@@ -3263,12 +3272,13 @@ func testChannelDeleteMemberStore(t *testing.T, ss store.Store) {
func testChannelStoreGetChannels(t *testing.T, ss store.Store) {
team := model.NewId()
o1 := model.Channel{}
o1 := &model.Channel{}
o1.TeamId = team
o1.DisplayName = "Channel1"
o1.Name = NewTestId()
o1.Type = model.ChannelTypeOpen
_, nErr := ss.Channel().Save(&o1, -1)
var nErr error
o1, nErr = ss.Channel().Save(o1, -1)
require.NoError(t, nErr)
o2 := model.Channel{}
@@ -3315,7 +3325,10 @@ func testChannelStoreGetChannels(t *testing.T, ss store.Store) {
_, err = ss.Channel().SaveMember(&m4)
require.NoError(t, err)
list, nErr := ss.Channel().GetChannels(o1.TeamId, m1.UserId, false, 0)
list, nErr := ss.Channel().GetChannels(o1.TeamId, m1.UserId, &model.ChannelSearchOpts{
IncludeDeleted: false,
LastDeleteAt: 0,
})
require.NoError(t, nErr)
require.Len(t, list, 3)
require.Equal(t, o1.Id, list[0].Id, "missing channel")
@@ -3342,6 +3355,25 @@ func testChannelStoreGetChannels(t *testing.T, ss store.Store) {
_, ok = ids4[o1.Id]
require.True(t, ok, "missing channel")
// Sleeping to guarantee that the
// UpdateAt is different.
// The proper way would be to set UpdateAt during channel creation itself,
// but the *Channel.PreSave method ignores any existing CreateAt value.
// TODO: check if using an existing CreateAt breaks anything.
time.Sleep(time.Millisecond)
now := model.GetMillis()
_, nErr = ss.Channel().Update(o1)
require.NoError(t, nErr)
list, nErr = ss.Channel().GetChannels(o1.TeamId, m1.UserId, &model.ChannelSearchOpts{
IncludeDeleted: false,
LastUpdateAt: int(now),
})
require.NoError(t, nErr)
// should return 1
require.Len(t, list, 1)
nErr = ss.Channel().Delete(o2.Id, 10)
require.NoError(t, nErr)
@@ -3349,13 +3381,19 @@ func testChannelStoreGetChannels(t *testing.T, ss store.Store) {
require.NoError(t, nErr)
// should return 1
list, nErr = ss.Channel().GetChannels(o1.TeamId, m1.UserId, false, 0)
list, nErr = ss.Channel().GetChannels(o1.TeamId, m1.UserId, &model.ChannelSearchOpts{
IncludeDeleted: false,
LastDeleteAt: 0,
})
require.NoError(t, nErr)
require.Len(t, list, 1)
require.Equal(t, o1.Id, list[0].Id, "missing channel")
// Should return all
list, nErr = ss.Channel().GetChannels(o1.TeamId, m1.UserId, true, 0)
list, nErr = ss.Channel().GetChannels(o1.TeamId, m1.UserId, &model.ChannelSearchOpts{
IncludeDeleted: true,
LastDeleteAt: 0,
})
require.NoError(t, nErr)
require.Len(t, list, 3)
require.Equal(t, o1.Id, list[0].Id, "missing channel")
@@ -3363,7 +3401,10 @@ func testChannelStoreGetChannels(t *testing.T, ss store.Store) {
require.Equal(t, o3.Id, list[2].Id, "missing channel")
// Should still return all
list, nErr = ss.Channel().GetChannels(o1.TeamId, m1.UserId, true, 10)
list, nErr = ss.Channel().GetChannels(o1.TeamId, m1.UserId, &model.ChannelSearchOpts{
IncludeDeleted: true,
LastDeleteAt: 10,
})
require.NoError(t, nErr)
require.Len(t, list, 3)
require.Equal(t, o1.Id, list[0].Id, "missing channel")
@@ -3371,7 +3412,10 @@ func testChannelStoreGetChannels(t *testing.T, ss store.Store) {
require.Equal(t, o3.Id, list[2].Id, "missing channel")
// Should return 2
list, nErr = ss.Channel().GetChannels(o1.TeamId, m1.UserId, true, 20)
list, nErr = ss.Channel().GetChannels(o1.TeamId, m1.UserId, &model.ChannelSearchOpts{
IncludeDeleted: true,
LastDeleteAt: 20,
})
require.NoError(t, nErr)
require.Len(t, list, 2)
require.Equal(t, o1.Id, list[0].Id, "missing channel")
@@ -3399,6 +3443,147 @@ func testChannelStoreGetChannels(t *testing.T, ss store.Store) {
ss.Channel().InvalidateAllChannelMembersForUser(m1.UserId)
}
func testChannelStoreGetChannelsWithCursor(t *testing.T, ss store.Store) {
teamID := model.NewId()
o1 := &model.Channel{}
o1.TeamId = teamID
o1.DisplayName = "Channel1"
o1.Name = NewTestId()
o1.Type = model.ChannelTypeOpen
var nErr error
o1, nErr = ss.Channel().Save(o1, -1)
require.NoError(t, nErr)
o2 := model.Channel{}
o2.TeamId = teamID
o2.DisplayName = "Channel2"
o2.Name = NewTestId()
o2.Type = model.ChannelTypeOpen
_, nErr = ss.Channel().Save(&o2, -1)
require.NoError(t, nErr)
o3 := model.Channel{}
o3.TeamId = teamID
o3.DisplayName = "Channel3"
o3.Name = NewTestId()
o3.Type = model.ChannelTypeOpen
_, nErr = ss.Channel().Save(&o3, -1)
require.NoError(t, nErr)
m1 := model.ChannelMember{}
m1.ChannelId = o1.Id
m1.UserId = model.NewId()
m1.NotifyProps = model.GetDefaultChannelNotifyProps()
_, err := ss.Channel().SaveMember(&m1)
require.NoError(t, err)
m2 := model.ChannelMember{}
m2.ChannelId = o1.Id
m2.UserId = model.NewId()
m2.NotifyProps = model.GetDefaultChannelNotifyProps()
_, err = ss.Channel().SaveMember(&m2)
require.NoError(t, err)
m3 := model.ChannelMember{}
m3.ChannelId = o2.Id
m3.UserId = m1.UserId
m3.NotifyProps = model.GetDefaultChannelNotifyProps()
_, err = ss.Channel().SaveMember(&m3)
require.NoError(t, err)
m4 := model.ChannelMember{}
m4.ChannelId = o3.Id
m4.UserId = m1.UserId
m4.NotifyProps = model.GetDefaultChannelNotifyProps()
_, err = ss.Channel().SaveMember(&m4)
require.NoError(t, err)
list, nErr := ss.Channel().GetChannelsWithCursor(o1.TeamId, m1.UserId, &model.ChannelSearchOpts{
IncludeDeleted: false,
LastDeleteAt: 0,
PerPage: model.NewInt(2),
}, "")
require.NoError(t, nErr)
require.Len(t, list, 2)
require.Equal(t, teamID, list[0].TeamId, "incorrect teamID")
require.Equal(t, teamID, list[1].TeamId, "incorrect teamID")
list, nErr = ss.Channel().GetChannelsWithCursor(o1.TeamId, m1.UserId, &model.ChannelSearchOpts{
IncludeDeleted: false,
LastDeleteAt: 0,
PerPage: model.NewInt(2),
}, list[1].Id)
require.NoError(t, nErr)
require.Len(t, list, 1)
require.Equal(t, teamID, list[0].TeamId, "incorrect teamID")
// Sleeping to guarantee that the
// UpdateAt is different.
// The proper way would be to set UpdateAt during channel creation itself,
// but the *Channel.PreSave method ignores any existing CreateAt value.
// TODO: check if using an existing CreateAt breaks anything.
time.Sleep(time.Millisecond)
now := model.GetMillis()
_, nErr = ss.Channel().Update(o1)
require.NoError(t, nErr)
list, nErr = ss.Channel().GetChannelsWithCursor(o1.TeamId, m1.UserId, &model.ChannelSearchOpts{
IncludeDeleted: false,
LastUpdateAt: int(now),
}, "")
require.NoError(t, nErr)
// should return 1
require.Len(t, list, 1)
nErr = ss.Channel().Delete(o2.Id, 10)
require.NoError(t, nErr)
nErr = ss.Channel().Delete(o3.Id, 20)
require.NoError(t, nErr)
// should return 1
list, nErr = ss.Channel().GetChannelsWithCursor(o1.TeamId, m1.UserId, &model.ChannelSearchOpts{
IncludeDeleted: false,
LastDeleteAt: 0,
}, "")
require.NoError(t, nErr)
require.Len(t, list, 1)
// Should return all
list, nErr = ss.Channel().GetChannelsWithCursor(o1.TeamId, m1.UserId, &model.ChannelSearchOpts{
IncludeDeleted: true,
LastDeleteAt: 0,
PerPage: model.NewInt(2),
}, "")
require.NoError(t, nErr)
require.Len(t, list, 2)
list, nErr = ss.Channel().GetChannelsWithCursor(o1.TeamId, m1.UserId, &model.ChannelSearchOpts{
IncludeDeleted: true,
LastDeleteAt: 0,
PerPage: model.NewInt(2),
}, list[1].Id)
require.NoError(t, nErr)
require.Len(t, list, 1)
// Should still return all
list, nErr = ss.Channel().GetChannelsWithCursor(o1.TeamId, m1.UserId, &model.ChannelSearchOpts{
IncludeDeleted: true,
LastDeleteAt: 10,
}, "")
require.NoError(t, nErr)
require.Len(t, list, 3)
// Should return 2
list, nErr = ss.Channel().GetChannelsWithCursor(o1.TeamId, m1.UserId, &model.ChannelSearchOpts{
IncludeDeleted: true,
LastDeleteAt: 20,
}, "")
require.NoError(t, nErr)
require.Len(t, list, 2)
}
func testChannelStoreGetChannelsByUser(t *testing.T, ss store.Store) {
team := model.NewId()
team2 := model.NewId()
@@ -4191,6 +4376,120 @@ func testChannelStoreGetMembersForUser(t *testing.T, ss store.Store) {
})
}
func testChannelStoreGetMembersForUserWithCursor(t *testing.T, ss store.Store) {
t1 := model.Team{}
t1.DisplayName = "Team1"
t1.Name = NewTestId()
t1.Email = MakeEmail()
t1.Type = model.TeamOpen
_, err := ss.Team().Save(&t1)
require.NoError(t, err)
o1 := model.Channel{}
o1.TeamId = t1.Id
o1.DisplayName = "Channel1"
o1.Name = NewTestId()
o1.Type = model.ChannelTypeOpen
_, nErr := ss.Channel().Save(&o1, -1)
require.NoError(t, nErr)
o2 := model.Channel{}
o2.TeamId = o1.TeamId
o2.DisplayName = "Channel2"
o2.Name = NewTestId()
o2.Type = model.ChannelTypeOpen
_, nErr = ss.Channel().Save(&o2, -1)
require.NoError(t, nErr)
m1 := model.ChannelMember{}
m1.ChannelId = o1.Id
m1.UserId = model.NewId()
m1.NotifyProps = model.GetDefaultChannelNotifyProps()
_, err = ss.Channel().SaveMember(&m1)
require.NoError(t, err)
m2 := model.ChannelMember{}
m2.ChannelId = o2.Id
m2.UserId = m1.UserId
m2.NotifyProps = model.GetDefaultChannelNotifyProps()
_, err = ss.Channel().SaveMember(&m2)
require.NoError(t, err)
t.Run("with channels", func(t *testing.T) {
var members model.ChannelMembers
members, err = ss.Channel().GetMembersForUserWithCursor(m1.UserId, "", "", 1, 0)
require.NoError(t, err)
assert.Len(t, members, 1)
members, err = ss.Channel().GetMembersForUserWithCursor(m1.UserId, "", "", 3, 0)
require.NoError(t, err)
assert.Len(t, members, 2)
members, err = ss.Channel().GetMembersForUserWithCursor(m1.UserId, members[0].ChannelId, m1.UserId, 1, 0)
require.NoError(t, err)
assert.Len(t, members, 1)
})
t.Run("with channels and direct messages", func(t *testing.T) {
user := model.User{Id: m1.UserId}
u1 := model.User{Id: model.NewId()}
u2 := model.User{Id: model.NewId()}
u3 := model.User{Id: model.NewId()}
u4 := model.User{Id: model.NewId()}
_, nErr = ss.Channel().CreateDirectChannel(&u1, &user)
require.NoError(t, nErr)
_, nErr = ss.Channel().CreateDirectChannel(&u2, &user)
require.NoError(t, nErr)
// other user direct message
_, nErr = ss.Channel().CreateDirectChannel(&u3, &u4)
require.NoError(t, nErr)
members, err2 := ss.Channel().GetMembersForUserWithCursor(m1.UserId, "", "", 10, 0)
require.NoError(t, err2)
assert.Len(t, members, 4)
members, err2 = ss.Channel().GetMembersForUserWithCursor(m1.UserId, "", "", 2, 0)
require.NoError(t, err2)
assert.Len(t, members, 2)
members, err2 = ss.Channel().GetMembersForUserWithCursor(m1.UserId, members[1].ChannelId, m1.UserId, 2, 0)
require.NoError(t, err2)
assert.Len(t, members, 2)
})
t.Run("with channels, direct channels and group messages", func(t *testing.T) {
userIds := []string{model.NewId(), model.NewId(), model.NewId(), m1.UserId}
group := &model.Channel{
Name: model.GetGroupNameFromUserIds(userIds),
DisplayName: "test",
Type: model.ChannelTypeGroup,
}
var channel *model.Channel
channel, nErr = ss.Channel().Save(group, 10000)
require.NoError(t, nErr)
for _, userId := range userIds {
cm := &model.ChannelMember{
UserId: userId,
ChannelId: channel.Id,
NotifyProps: model.GetDefaultChannelNotifyProps(),
SchemeUser: true,
}
_, err = ss.Channel().SaveMember(cm)
require.NoError(t, err)
}
members, err := ss.Channel().GetMembersForUserWithCursor(m1.UserId, "", "", 10, 0)
require.NoError(t, err)
assert.Len(t, members, 5)
members, err = ss.Channel().GetMembersForUserWithCursor(m1.UserId, "", "", 2, 0)
require.NoError(t, err)
assert.Len(t, members, 2)
members, err = ss.Channel().GetMembersForUserWithCursor(m1.UserId, members[1].ChannelId, m1.UserId, 10, 0)
require.NoError(t, err)
assert.Len(t, members, 3)
})
}
func testChannelStoreGetMembersForUserWithPagination(t *testing.T, ss store.Store) {
t1 := model.Team{
DisplayName: "team1",
@@ -6072,6 +6371,62 @@ func testChannelStoreGetMembersByChannelIds(t *testing.T, ss store.Store) {
})
}
func testChannelStoreGetMembersInfoByChannelIds(t *testing.T, ss store.Store) {
u, err := ss.User().Save(&model.User{
Username: "user.test",
Email: MakeEmail(),
Nickname: model.NewId(),
})
require.NoError(t, err)
// Create a couple channels and add the user to them
channel1, err := ss.Channel().Save(&model.Channel{
TeamId: model.NewId(),
DisplayName: model.NewId(),
Name: model.NewId(),
Type: model.ChannelTypeOpen,
}, -1)
require.NoError(t, err)
channel2, err := ss.Channel().Save(&model.Channel{
TeamId: model.NewId(),
DisplayName: model.NewId(),
Name: model.NewId(),
Type: model.ChannelTypeOpen,
}, -1)
require.NoError(t, err)
_, err = ss.Channel().SaveMember(&model.ChannelMember{
ChannelId: channel1.Id,
UserId: u.Id,
NotifyProps: model.GetDefaultChannelNotifyProps(),
})
require.NoError(t, err)
_, err = ss.Channel().SaveMember(&model.ChannelMember{
ChannelId: channel2.Id,
UserId: u.Id,
NotifyProps: model.GetDefaultChannelNotifyProps(),
})
require.NoError(t, err)
t.Run("should return the user's members for the given channels", func(t *testing.T) {
result, nErr := ss.Channel().GetMembersInfoByChannelIds([]string{channel1.Id, channel2.Id})
require.NoError(t, nErr)
assert.Len(t, result, 2)
for _, item := range result {
assert.Len(t, item, 1)
assert.Equal(t, u.Id, item[0].Id)
}
})
t.Run("should not error or return anything for invalid channel IDs", func(t *testing.T) {
_, err := ss.Channel().GetMembersInfoByChannelIds([]string{model.NewId(), model.NewId()})
var nfErr *store.ErrNotFound
require.True(t, errors.As(err, &nfErr))
})
}
func testChannelStoreSearchGroupChannels(t *testing.T, ss store.Store) {
// Users
u1 := &model.User{}

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

@@ -35,6 +35,29 @@ func (_m *ChannelMemberHistoryStore) DeleteOrphanedRows(limit int) (int64, error
return r0, r1
}
// GetChannelsLeftSince provides a mock function with given fields: userID, since
func (_m *ChannelMemberHistoryStore) GetChannelsLeftSince(userID string, since int64) ([]string, error) {
ret := _m.Called(userID, since)
var r0 []string
if rf, ok := ret.Get(0).(func(string, int64) []string); ok {
r0 = rf(userID, since)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]string)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(string, int64) error); ok {
r1 = rf(userID, since)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// GetUsersInChannelDuring provides a mock function with given fields: startTime, endTime, channelID
func (_m *ChannelMemberHistoryStore) GetUsersInChannelDuring(startTime int64, endTime int64, channelID string) ([]*model.ChannelMemberHistoryResult, error) {
ret := _m.Called(startTime, endTime, channelID)

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

@@ -674,13 +674,13 @@ func (_m *ChannelStore) GetChannelUnread(channelID string, userID string) (*mode
return r0, r1
}
// GetChannels provides a mock function with given fields: teamID, userID, includeDeleted, lastDeleteAt
func (_m *ChannelStore) GetChannels(teamID string, userID string, includeDeleted bool, lastDeleteAt int) (model.ChannelList, error) {
ret := _m.Called(teamID, userID, includeDeleted, lastDeleteAt)
// GetChannels provides a mock function with given fields: teamID, userID, opts
func (_m *ChannelStore) GetChannels(teamID string, userID string, opts *model.ChannelSearchOpts) (model.ChannelList, error) {
ret := _m.Called(teamID, userID, opts)
var r0 model.ChannelList
if rf, ok := ret.Get(0).(func(string, string, bool, int) model.ChannelList); ok {
r0 = rf(teamID, userID, includeDeleted, lastDeleteAt)
if rf, ok := ret.Get(0).(func(string, string, *model.ChannelSearchOpts) model.ChannelList); ok {
r0 = rf(teamID, userID, opts)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(model.ChannelList)
@@ -688,8 +688,8 @@ func (_m *ChannelStore) GetChannels(teamID string, userID string, includeDeleted
}
var r1 error
if rf, ok := ret.Get(1).(func(string, string, bool, int) error); ok {
r1 = rf(teamID, userID, includeDeleted, lastDeleteAt)
if rf, ok := ret.Get(1).(func(string, string, *model.ChannelSearchOpts) error); ok {
r1 = rf(teamID, userID, opts)
} else {
r1 = ret.Error(1)
}
@@ -789,6 +789,29 @@ func (_m *ChannelStore) GetChannelsByUser(userID string, includeDeleted bool, la
return r0, r1
}
// GetChannelsWithCursor provides a mock function with given fields: teamId, userId, opts, afterChannelID
func (_m *ChannelStore) GetChannelsWithCursor(teamId string, userId string, opts *model.ChannelSearchOpts, afterChannelID string) (model.ChannelList, error) {
ret := _m.Called(teamId, userId, opts, afterChannelID)
var r0 model.ChannelList
if rf, ok := ret.Get(0).(func(string, string, *model.ChannelSearchOpts, string) model.ChannelList); ok {
r0 = rf(teamId, userId, opts, afterChannelID)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(model.ChannelList)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(string, string, *model.ChannelSearchOpts, string) error); ok {
r1 = rf(teamId, userId, opts, afterChannelID)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// GetChannelsWithTeamDataByIds provides a mock function with given fields: channelIds, includeDeleted
func (_m *ChannelStore) GetChannelsWithTeamDataByIds(channelIds []string, includeDeleted bool) ([]*model.ChannelWithTeamData, error) {
ret := _m.Called(channelIds, includeDeleted)
@@ -1121,6 +1144,29 @@ func (_m *ChannelStore) GetMembersForUser(teamID string, userID string) (model.C
return r0, r1
}
// GetMembersForUserWithCursor provides a mock function with given fields: userID, afterChannel, afterUser, limit, lastUpdateAt
func (_m *ChannelStore) GetMembersForUserWithCursor(userID string, afterChannel string, afterUser string, limit int, lastUpdateAt int) (model.ChannelMembers, error) {
ret := _m.Called(userID, afterChannel, afterUser, limit, lastUpdateAt)
var r0 model.ChannelMembers
if rf, ok := ret.Get(0).(func(string, string, string, int, int) model.ChannelMembers); ok {
r0 = rf(userID, afterChannel, afterUser, limit, lastUpdateAt)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(model.ChannelMembers)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(string, string, string, int, int) error); ok {
r1 = rf(userID, afterChannel, afterUser, limit, lastUpdateAt)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// GetMembersForUserWithPagination provides a mock function with given fields: userID, page, perPage
func (_m *ChannelStore) GetMembersForUserWithPagination(userID string, page int, perPage int) (model.ChannelMembersWithTeamData, error) {
ret := _m.Called(userID, page, perPage)
@@ -1144,6 +1190,29 @@ func (_m *ChannelStore) GetMembersForUserWithPagination(userID string, page int,
return r0, r1
}
// GetMembersInfoByChannelIds provides a mock function with given fields: channelIDs
func (_m *ChannelStore) GetMembersInfoByChannelIds(channelIDs []string) (map[string][]*model.User, error) {
ret := _m.Called(channelIDs)
var r0 map[string][]*model.User
if rf, ok := ret.Get(0).(func([]string) map[string][]*model.User); ok {
r0 = rf(channelIDs)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(map[string][]*model.User)
}
}
var r1 error
if rf, ok := ret.Get(1).(func([]string) error); ok {
r1 = rf(channelIDs)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// GetMoreChannels provides a mock function with given fields: teamID, userID, offset, limit
func (_m *ChannelStore) GetMoreChannels(teamID string, userID string, offset int, limit int) (model.ChannelList, error) {
ret := _m.Called(teamID, userID, offset, limit)

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

@@ -1013,10 +1013,10 @@ func (s *TimerLayerChannelStore) GetChannelUnread(channelID string, userID strin
return result, err
}
func (s *TimerLayerChannelStore) GetChannels(teamID string, userID string, includeDeleted bool, lastDeleteAt int) (model.ChannelList, error) {
func (s *TimerLayerChannelStore) GetChannels(teamID string, userID string, opts *model.ChannelSearchOpts) (model.ChannelList, error) {
start := timemodule.Now()
result, err := s.ChannelStore.GetChannels(teamID, userID, includeDeleted, lastDeleteAt)
result, err := s.ChannelStore.GetChannels(teamID, userID, opts)
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
if s.Root.Metrics != nil {
@@ -1093,6 +1093,22 @@ func (s *TimerLayerChannelStore) GetChannelsByUser(userID string, includeDeleted
return result, err
}
func (s *TimerLayerChannelStore) GetChannelsWithCursor(teamId string, userId string, opts *model.ChannelSearchOpts, afterChannelID string) (model.ChannelList, error) {
start := timemodule.Now()
result, err := s.ChannelStore.GetChannelsWithCursor(teamId, userId, opts, afterChannelID)
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
if s.Root.Metrics != nil {
success := "false"
if err == nil {
success = "true"
}
s.Root.Metrics.ObserveStoreMethodDuration("ChannelStore.GetChannelsWithCursor", success, elapsed)
}
return result, err
}
func (s *TimerLayerChannelStore) GetChannelsWithTeamDataByIds(channelIds []string, includeDeleted bool) ([]*model.ChannelWithTeamData, error) {
start := timemodule.Now()
@@ -1333,6 +1349,22 @@ func (s *TimerLayerChannelStore) GetMembersForUser(teamID string, userID string)
return result, err
}
func (s *TimerLayerChannelStore) GetMembersForUserWithCursor(userID string, afterChannel string, afterUser string, limit int, lastUpdateAt int) (model.ChannelMembers, error) {
start := timemodule.Now()
result, err := s.ChannelStore.GetMembersForUserWithCursor(userID, afterChannel, afterUser, limit, lastUpdateAt)
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
if s.Root.Metrics != nil {
success := "false"
if err == nil {
success = "true"
}
s.Root.Metrics.ObserveStoreMethodDuration("ChannelStore.GetMembersForUserWithCursor", success, elapsed)
}
return result, err
}
func (s *TimerLayerChannelStore) GetMembersForUserWithPagination(userID string, page int, perPage int) (model.ChannelMembersWithTeamData, error) {
start := timemodule.Now()
@@ -1349,6 +1381,22 @@ func (s *TimerLayerChannelStore) GetMembersForUserWithPagination(userID string,
return result, err
}
func (s *TimerLayerChannelStore) GetMembersInfoByChannelIds(channelIDs []string) (map[string][]*model.User, error) {
start := timemodule.Now()
result, err := s.ChannelStore.GetMembersInfoByChannelIds(channelIDs)
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
if s.Root.Metrics != nil {
success := "false"
if err == nil {
success = "true"
}
s.Root.Metrics.ObserveStoreMethodDuration("ChannelStore.GetMembersInfoByChannelIds", success, elapsed)
}
return result, err
}
func (s *TimerLayerChannelStore) GetMoreChannels(teamID string, userID string, offset int, limit int) (model.ChannelList, error) {
start := timemodule.Now()
@@ -2254,6 +2302,22 @@ func (s *TimerLayerChannelMemberHistoryStore) DeleteOrphanedRows(limit int) (int
return result, err
}
func (s *TimerLayerChannelMemberHistoryStore) GetChannelsLeftSince(userID string, since int64) ([]string, error) {
start := timemodule.Now()
result, err := s.ChannelMemberHistoryStore.GetChannelsLeftSince(userID, since)
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
if s.Root.Metrics != nil {
success := "false"
if err == nil {
success = "true"
}
s.Root.Metrics.ObserveStoreMethodDuration("ChannelMemberHistoryStore.GetChannelsLeftSince", success, elapsed)
}
return result, err
}
func (s *TimerLayerChannelMemberHistoryStore) GetUsersInChannelDuring(startTime int64, endTime int64, channelID string) ([]*model.ChannelMemberHistoryResult, error) {
start := timemodule.Now()