MM-25563: Add endpoint to fetch only archived channels (#15031)

Automatic Merge
Этот коммит содержится в:
Agniva De Sarker
2020-07-27 17:01:39 +05:30
коммит произвёл GitHub
родитель 29c8b58fc7
Коммит 77f7a97bee
18 изменённых файлов: 166 добавлений и 49 удалений

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

@@ -854,7 +854,17 @@ func getChannelsForTeamForUser(c *Context, w http.ResponseWriter, r *http.Reques
return
}
channels, err := c.App.GetChannelsForUser(c.Params.TeamId, c.Params.UserId, c.Params.IncludeDeleted)
query := r.URL.Query()
lastDeleteAt, nErr := strconv.Atoi(query.Get("last_delete_at"))
if nErr != nil {
lastDeleteAt = 0
}
if lastDeleteAt < 0 {
c.SetInvalidUrlParam("last_delete_at")
return
}
channels, err := c.App.GetChannelsForUser(c.Params.TeamId, c.Params.UserId, c.Params.IncludeDeleted, lastDeleteAt)
if err != nil {
c.Err = err
return
@@ -2047,7 +2057,7 @@ func updateCategoriesForTeamForUser(c *Context, w http.ResponseWriter, r *http.R
}
func validateUserChannels(operationName string, c *Context, teamId, userId string, channelIDs []string) *model.AppError {
channels, err := c.App.GetChannelsForUser(teamId, userId, false)
channels, err := c.App.GetChannelsForUser(teamId, userId, false, 0)
if err != nil {
return model.NewAppError("Api4."+operationName, "api.invalid_channel", nil, err.Error(), http.StatusBadRequest)
}

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

@@ -949,6 +949,18 @@ func TestGetChannelsForTeamForUser(t *testing.T) {
channels, resp = Client.GetChannelsForTeamForUser(th.BasicTeam.Id, th.BasicUser.Id, false, "")
CheckNoError(t, resp)
assert.Equal(t, 5, len(channels))
// Should return all channels including basicDeleted.
channels, resp = Client.GetChannelsForTeamForUser(th.BasicTeam.Id, th.BasicUser.Id, true, "")
CheckNoError(t, resp)
assert.Equal(t, 7, len(channels))
// Should stil return all channels including basicDeleted.
now := time.Now().Add(-time.Minute).Unix() * 1000
Client.GetChannelsForTeamAndUserWithLastDeleteAt(th.BasicTeam.Id, th.BasicUser.Id,
true, int(now), "")
CheckNoError(t, resp)
assert.Equal(t, 7, len(channels))
})
}

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

@@ -513,7 +513,7 @@ type AppIface interface {
GetChannelsByNames(channelNames []string, teamId string) ([]*model.Channel, *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)
GetChannelsForUser(teamId string, userId string, includeDeleted bool) (*model.ChannelList, *model.AppError)
GetChannelsForUser(teamId string, userId string, includeDeleted bool, lastDeleteAt int) (*model.ChannelList, *model.AppError)
GetChannelsUserNotIn(teamId string, userId string, offset int, limit int) (*model.ChannelList, *model.AppError)
GetClusterId() string
GetClusterStatus() []*model.ClusterInfo

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

@@ -1554,8 +1554,8 @@ func (a *App) GetChannelByNameForTeamName(channelName, teamName string, includeD
return result, nil
}
func (a *App) GetChannelsForUser(teamId string, userId string, includeDeleted bool) (*model.ChannelList, *model.AppError) {
list, err := a.Srv().Store.Channel().GetChannels(teamId, userId, includeDeleted)
func (a *App) GetChannelsForUser(teamId string, userId string, includeDeleted bool, lastDeleteAt int) (*model.ChannelList, *model.AppError) {
list, err := a.Srv().Store.Channel().GetChannels(teamId, userId, includeDeleted, lastDeleteAt)
if err != nil {
var nfErr *store.ErrNotFound
switch {

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

@@ -944,19 +944,19 @@ func TestGetChannelsForUser(t *testing.T) {
defer th.App.PermanentDeleteChannel(channel)
defer th.TearDown()
channelList, err := th.App.GetChannelsForUser(th.BasicTeam.Id, th.BasicUser.Id, false)
channelList, err := th.App.GetChannelsForUser(th.BasicTeam.Id, th.BasicUser.Id, false, 0)
require.Nil(t, err)
require.Len(t, *channelList, 4)
th.App.DeleteChannel(channel, th.BasicUser.Id)
// Now we get all the non-archived channels for the user
channelList, err = th.App.GetChannelsForUser(th.BasicTeam.Id, th.BasicUser.Id, false)
channelList, err = th.App.GetChannelsForUser(th.BasicTeam.Id, th.BasicUser.Id, false, 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.GetChannelsForUser(th.BasicTeam.Id, th.BasicUser.Id, true)
channelList, err = th.App.GetChannelsForUser(th.BasicTeam.Id, th.BasicUser.Id, true, 0)
require.Nil(t, err)
require.Len(t, *channelList, 4)
}

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

@@ -4650,7 +4650,7 @@ func (a *OpenTracingAppLayer) GetChannelsForSchemePage(scheme *model.Scheme, pag
return resultVar0, resultVar1
}
func (a *OpenTracingAppLayer) GetChannelsForUser(teamId string, userId string, includeDeleted bool) (*model.ChannelList, *model.AppError) {
func (a *OpenTracingAppLayer) GetChannelsForUser(teamId string, userId string, includeDeleted bool, lastDeleteAt int) (*model.ChannelList, *model.AppError) {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetChannelsForUser")
@@ -4662,7 +4662,7 @@ func (a *OpenTracingAppLayer) GetChannelsForUser(teamId string, userId string, i
}()
defer span.Finish()
resultVar0, resultVar1 := a.app.GetChannelsForUser(teamId, userId, includeDeleted)
resultVar0, resultVar1 := a.app.GetChannelsForUser(teamId, userId, includeDeleted, lastDeleteAt)
if resultVar1 != nil {
span.LogFields(spanlog.Error(resultVar1))

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

@@ -374,7 +374,7 @@ func (api *PluginAPI) GetChannelByNameForTeamName(teamName, channelName string,
}
func (api *PluginAPI) GetChannelsForTeamForUser(teamId, userId string, includeDeleted bool) ([]*model.Channel, *model.AppError) {
channels, err := api.app.GetChannelsForUser(teamId, userId, includeDeleted)
channels, err := api.app.GetChannelsForUser(teamId, userId, includeDeleted, 0)
if err != nil {
return nil, err
}

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

@@ -1003,7 +1003,7 @@ func (a *App) LeaveTeam(team *model.Team, user *model.User, requestorId string)
var channelList *model.ChannelList
var nErr error
if channelList, nErr = a.Srv().Store.Channel().GetChannels(team.Id, user.Id, true); nErr != nil {
if channelList, nErr = a.Srv().Store.Channel().GetChannels(team.Id, user.Id, true, 0); nErr != nil {
var nfErr *store.ErrNotFound
if errors.As(nErr, &nfErr) {
channelList = &model.ChannelList{}

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

@@ -966,7 +966,7 @@ func (a *App) invalidateUserChannelMembersCaches(userId string) *model.AppError
}
for _, team := range teamsForUser {
channelsForUser, err := a.GetChannelsForUser(team.Id, userId, false)
channelsForUser, err := a.GetChannelsForUser(team.Id, userId, false, 0)
if err != nil {
return err
}

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

@@ -153,7 +153,7 @@ 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)
channels, err := a.Srv().Store.Channel().GetChannels(teamid, userid, false, 0)
if err != nil {
mlog.Debug("Unable to get channels")
return "", false

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

@@ -2490,6 +2490,18 @@ func (c *Client4) GetChannelsForTeamForUser(teamId, userId string, includeDelete
return ChannelSliceFromJson(r.Body), BuildResponse(r)
}
// GetChannelsForTeamAndUserWithLastDeleteAt returns a list channels of a team for a user, additionally filtered with lastDeleteAt. This does not have any effect if includeDeleted is set to false.
func (c *Client4) GetChannelsForTeamAndUserWithLastDeleteAt(teamId, userId string, includeDeleted bool, lastDeleteAt int, etag string) ([]*Channel, *Response) {
route := fmt.Sprintf(c.GetUserRoute(userId) + c.GetTeamRoute(teamId) + "/channels")
route += fmt.Sprintf("?include_deleted=%v&last_delete_at=%d", includeDeleted, lastDeleteAt)
r, err := c.DoApiGet(route, etag)
if err != nil {
return nil, BuildErrorResponse(r, err)
}
defer closeBody(r)
return ChannelSliceFromJson(r.Body), BuildResponse(r)
}
// SearchChannels returns the channels on a team matching the provided search term.
func (c *Client4) SearchChannels(teamId string, search *ChannelSearch) ([]*Channel, *Response) {
r, err := c.DoApiPost(c.GetChannelsForTeamRoute(teamId)+"/search", search.ToJson())

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

@@ -990,7 +990,7 @@ func (s *OpenTracingLayerChannelStore) GetChannelUnread(channelId string, userId
return resultVar0, resultVar1
}
func (s *OpenTracingLayerChannelStore) GetChannels(teamId string, userId string, includeDeleted bool) (*model.ChannelList, error) {
func (s *OpenTracingLayerChannelStore) GetChannels(teamId string, userId string, includeDeleted bool, lastDeleteAt int) (*model.ChannelList, error) {
origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.GetChannels")
s.Root.Store.SetContext(newCtx)
@@ -999,7 +999,7 @@ func (s *OpenTracingLayerChannelStore) GetChannels(teamId string, userId string,
}()
defer span.Finish()
resultVar0, resultVar1 := s.ChannelStore.GetChannels(teamId, userId, includeDeleted)
resultVar0, resultVar1 := s.ChannelStore.GetChannels(teamId, userId, includeDeleted, lastDeleteAt)
if resultVar1 != nil {
span.LogFields(spanlog.Error(resultVar1))
ext.Error.Set(span, true)

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

@@ -133,7 +133,7 @@ func (s SearchPostStore) PermanentDeleteByChannel(channelID string) *model.AppEr
func (s SearchPostStore) searchPostsInTeamForUserByEngine(engine searchengine.SearchEngineInterface, paramsList []*model.SearchParams, userId, teamId string, isOrSearch, includeDeletedChannels bool, page, perPage int) (*model.PostSearchResults, *model.AppError) {
// We only allow the user to search in channels they are a member of.
userChannels, nErr := s.rootStore.Channel().GetChannels(teamId, userId, includeDeletedChannels)
userChannels, nErr := s.rootStore.Channel().GetChannels(teamId, userId, includeDeletedChannels, 0)
if nErr != nil {
mlog.Error("error getting channel for user", mlog.Err(nErr))
var nfErr *store.ErrNotFound

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

@@ -1134,14 +1134,43 @@ func (s SqlChannelStore) PermanentDeleteMembersByChannel(channelId string) *mode
return nil
}
func (s SqlChannelStore) GetChannels(teamId string, userId string, includeDeleted bool) (*model.ChannelList, error) {
query := "SELECT Channels.* FROM Channels, ChannelMembers WHERE Id = ChannelId AND UserId = :UserId AND DeleteAt = 0 AND (TeamId = :TeamId OR TeamId = '') ORDER BY DisplayName"
if includeDeleted {
query = "SELECT Channels.* FROM Channels, ChannelMembers WHERE Id = ChannelId AND UserId = :UserId AND (TeamId = :TeamId OR TeamId = '') ORDER BY DisplayName"
}
channels := &model.ChannelList{}
_, err := s.GetReplica().Select(channels, query, map[string]interface{}{"TeamId": teamId, "UserId": userId})
func (s SqlChannelStore) GetChannels(teamId string, userId string, includeDeleted bool, lastDeleteAt int) (*model.ChannelList, error) {
query := s.getQueryBuilder().
Select("Channels.*").
From("Channels, ChannelMembers").
Where(
sq.And{
sq.Expr("Id = ChannelId"),
sq.Eq{"UserId": userId},
sq.Or{
sq.Eq{"TeamId": teamId},
sq.Eq{"TeamId": ""},
},
},
).
OrderBy("DisplayName")
if includeDeleted {
if lastDeleteAt != 0 {
// We filter by non-archived, and archived >= a timestamp.
query = query.Where(sq.Or{
sq.Eq{"DeleteAt": 0},
sq.GtOrEq{"DeleteAt": lastDeleteAt},
})
}
// If 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})
}
channels := &model.ChannelList{}
sql, args, err := query.ToSql()
if err != nil {
return nil, errors.Wrapf(err, "getchannels_tosql")
}
_, err = s.GetReplica().Select(channels, sql, args...)
if err != nil {
return nil, errors.Wrapf(err, "failed to get channels with TeamId=%s and UserId=%s", teamId, userId)
}

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

@@ -154,7 +154,7 @@ 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) (*model.ChannelList, error)
GetChannels(teamId string, userId string, includeDeleted bool, lastDeleteAt int) (*model.ChannelList, error)
GetAllChannels(page, perPage int, opts ChannelSearchOpts) (*model.ChannelListWithTeamData, error)
GetAllChannelsCount(opts ChannelSearchOpts) (int64, error)
GetMoreChannels(teamId string, userId string, offset int, limit int) (*model.ChannelList, error)

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

@@ -618,7 +618,7 @@ func testChannelStoreDelete(t *testing.T, ss store.Store) {
nErr = ss.Channel().Delete(o3.Id, model.GetMillis())
require.Nil(t, nErr, nErr)
list, nErr := ss.Channel().GetChannels(o1.TeamId, m1.UserId, false)
list, nErr := ss.Channel().GetChannels(o1.TeamId, m1.UserId, false, 0)
require.Nil(t, nErr)
require.Len(t, *list, 1, "invalid number of channels")
@@ -629,7 +629,7 @@ func testChannelStoreDelete(t *testing.T, ss store.Store) {
cresult := ss.Channel().PermanentDelete(o2.Id)
require.Nil(t, cresult)
list, nErr = ss.Channel().GetChannels(o1.TeamId, m1.UserId, false)
list, nErr = ss.Channel().GetChannels(o1.TeamId, m1.UserId, false, 0)
if assert.NotNil(t, nErr) {
var nfErr *store.ErrNotFound
require.True(t, errors.As(nErr, &nfErr))
@@ -3111,20 +3111,29 @@ func testChannelDeleteMemberStore(t *testing.T, ss store.Store) {
}
func testChannelStoreGetChannels(t *testing.T, ss store.Store) {
o2 := model.Channel{}
o2.TeamId = model.NewId()
o2.DisplayName = "Channel2"
o2.Name = "zz" + model.NewId() + "b"
o2.Type = model.CHANNEL_OPEN
_, nErr := ss.Channel().Save(&o2, -1)
require.Nil(t, nErr)
team := model.NewId()
o1 := model.Channel{}
o1.TeamId = model.NewId()
o1.TeamId = team
o1.DisplayName = "Channel1"
o1.Name = "zz" + model.NewId() + "b"
o1.Type = model.CHANNEL_OPEN
_, nErr = ss.Channel().Save(&o1, -1)
_, nErr := ss.Channel().Save(&o1, -1)
require.Nil(t, nErr)
o2 := model.Channel{}
o2.TeamId = team
o2.DisplayName = "Channel2"
o2.Name = "zz" + model.NewId() + "b"
o2.Type = model.CHANNEL_OPEN
_, nErr = ss.Channel().Save(&o2, -1)
require.Nil(t, nErr)
o3 := model.Channel{}
o3.TeamId = team
o3.DisplayName = "Channel3"
o3.Name = "zz" + model.NewId() + "b"
o3.Type = model.CHANNEL_OPEN
_, nErr = ss.Channel().Save(&o3, -1)
require.Nil(t, nErr)
m1 := model.ChannelMember{}
@@ -3143,14 +3152,24 @@ func testChannelStoreGetChannels(t *testing.T, ss store.Store) {
m3 := model.ChannelMember{}
m3.ChannelId = o2.Id
m3.UserId = model.NewId()
m3.UserId = m1.UserId
m3.NotifyProps = model.GetDefaultChannelNotifyProps()
_, err = ss.Channel().SaveMember(&m3)
require.Nil(t, err)
list, nErr := ss.Channel().GetChannels(o1.TeamId, m1.UserId, false)
m4 := model.ChannelMember{}
m4.ChannelId = o3.Id
m4.UserId = m1.UserId
m4.NotifyProps = model.GetDefaultChannelNotifyProps()
_, err = ss.Channel().SaveMember(&m4)
require.Nil(t, err)
list, nErr := ss.Channel().GetChannels(o1.TeamId, m1.UserId, false, 0)
require.Nil(t, nErr)
require.Len(t, *list, 3)
require.Equal(t, o1.Id, (*list)[0].Id, "missing channel")
require.Equal(t, o2.Id, (*list)[1].Id, "missing channel")
require.Equal(t, o3.Id, (*list)[2].Id, "missing channel")
ids, err := ss.Channel().GetAllChannelMembersForUser(m1.UserId, false, false)
require.Nil(t, err)
@@ -3172,11 +3191,46 @@ func testChannelStoreGetChannels(t *testing.T, ss store.Store) {
_, ok = ids4[o1.Id]
require.True(t, ok, "missing channel")
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().GetChannels(o1.TeamId, m1.UserId, false, 0)
require.Nil(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)
require.Nil(t, nErr)
require.Len(t, *list, 3)
require.Equal(t, o1.Id, (*list)[0].Id, "missing channel")
require.Equal(t, o2.Id, (*list)[1].Id, "missing channel")
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)
require.Nil(t, nErr)
require.Len(t, *list, 3)
require.Equal(t, o1.Id, (*list)[0].Id, "missing channel")
require.Equal(t, o2.Id, (*list)[1].Id, "missing channel")
require.Equal(t, o3.Id, (*list)[2].Id, "missing channel")
// Should return 2
list, nErr = ss.Channel().GetChannels(o1.TeamId, m1.UserId, true, 20)
require.Nil(t, nErr)
require.Len(t, *list, 2)
require.Equal(t, o1.Id, (*list)[0].Id, "missing channel")
require.Equal(t, o3.Id, (*list)[1].Id, "missing channel")
require.True(
t,
ss.Channel().IsUserInChannelUseCache(m1.UserId, o1.Id),
"missing channel")
require.False(
require.True(
t,
ss.Channel().IsUserInChannelUseCache(m1.UserId, o2.Id),
"missing channel")

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

@@ -638,13 +638,13 @@ func (_m *ChannelStore) GetChannelUnread(channelId string, userId string) (*mode
return r0, r1
}
// GetChannels provides a mock function with given fields: teamId, userId, includeDeleted
func (_m *ChannelStore) GetChannels(teamId string, userId string, includeDeleted bool) (*model.ChannelList, error) {
ret := _m.Called(teamId, userId, includeDeleted)
// 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)
var r0 *model.ChannelList
if rf, ok := ret.Get(0).(func(string, string, bool) *model.ChannelList); ok {
r0 = rf(teamId, userId, includeDeleted)
if rf, ok := ret.Get(0).(func(string, string, bool, int) *model.ChannelList); ok {
r0 = rf(teamId, userId, includeDeleted, lastDeleteAt)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.ChannelList)
@@ -652,8 +652,8 @@ func (_m *ChannelStore) GetChannels(teamId string, userId string, includeDeleted
}
var r1 error
if rf, ok := ret.Get(1).(func(string, string, bool) error); ok {
r1 = rf(teamId, userId, includeDeleted)
if rf, ok := ret.Get(1).(func(string, string, bool, int) error); ok {
r1 = rf(teamId, userId, includeDeleted, lastDeleteAt)
} else {
r1 = ret.Error(1)
}

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

@@ -920,10 +920,10 @@ func (s *TimerLayerChannelStore) GetChannelUnread(channelId string, userId strin
return resultVar0, resultVar1
}
func (s *TimerLayerChannelStore) GetChannels(teamId string, userId string, includeDeleted bool) (*model.ChannelList, error) {
func (s *TimerLayerChannelStore) GetChannels(teamId string, userId string, includeDeleted bool, lastDeleteAt int) (*model.ChannelList, error) {
start := timemodule.Now()
resultVar0, resultVar1 := s.ChannelStore.GetChannels(teamId, userId, includeDeleted)
resultVar0, resultVar1 := s.ChannelStore.GetChannels(teamId, userId, includeDeleted, lastDeleteAt)
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
if s.Root.Metrics != nil {