MM-19337 Enable users to view archived channels (#12995)

* First pass at searching archived channels

* Create endpoint for archived channels

* Update test for GetPublicChannelsForTeam

* Fix unit test for archived channels

* Rename includeDeleted to onlyDeleted

* Remove new /archived endpoint in favour of existing /deleted endpoint

* Fix broken test

* Remove manage team permission from /deleted endpoint

* Fix deletedChannels test

* Test for searching archived channels

* Only return private deleted channels user was a member of

* SearchArchivedChannels also searches private channels (user is a member of)

* Remove for loop to simplify append

* Remove userId from Client4 searcArchivedChannels
Этот коммит содержится в:
Valentijn Nieman
2019-11-11 17:15:19 -05:00
коммит произвёл Saturnino Abril
родитель 1930cc6a11
Коммит 36f3b14420
9 изменённых файлов: 280 добавлений и 23 удалений

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

@@ -1036,7 +1036,7 @@ func (s SqlChannelStore) GetPublicChannelsForTeam(teamId string, offset int, lim
PublicChannels pc ON (pc.Id = Channels.Id)
WHERE
pc.TeamId = :TeamId
AND pc.DeleteAt = 0
AND pc.DeleteAt = 0
ORDER BY pc.DisplayName
LIMIT :Limit
OFFSET :Offset
@@ -1242,10 +1242,24 @@ func (s SqlChannelStore) GetDeletedByName(teamId string, name string) (*model.Ch
return &channel, nil
}
func (s SqlChannelStore) GetDeleted(teamId string, offset int, limit int) (*model.ChannelList, *model.AppError) {
func (s SqlChannelStore) GetDeleted(teamId string, offset int, limit int, userId string) (*model.ChannelList, *model.AppError) {
channels := &model.ChannelList{}
if _, err := s.GetReplica().Select(channels, "SELECT * FROM Channels WHERE (TeamId = :TeamId OR TeamId = '') AND DeleteAt != 0 ORDER BY DisplayName LIMIT :Limit OFFSET :Offset", map[string]interface{}{"TeamId": teamId, "Limit": limit, "Offset": offset}); err != nil {
query := `
SELECT * FROM Channels
WHERE (TeamId = :TeamId OR TeamId = '')
AND DeleteAt != 0
AND Type != 'P'
UNION
SELECT * FROM Channels
WHERE (TeamId = :TeamId OR TeamId = '')
AND DeleteAt != 0
AND Type = 'P'
AND Id IN (SELECT ChannelId FROM ChannelMembers WHERE UserId = :UserId)
ORDER BY DisplayName LIMIT :Limit OFFSET :Offset
`
if _, err := s.GetReplica().Select(channels, query, map[string]interface{}{"TeamId": teamId, "Limit": limit, "Offset": offset, "UserId": userId}); err != nil {
if err == sql.ErrNoRows {
return nil, model.NewAppError("SqlChannelStore.GetDeleted", "store.sql_channel.get_deleted.missing.app_error", nil, "teamId="+teamId+", "+err.Error(), http.StatusNotFound)
}
@@ -2154,6 +2168,57 @@ func (s SqlChannelStore) SearchInTeam(teamId string, term string, includeDeleted
})
}
func (s SqlChannelStore) SearchArchivedInTeam(teamId string, term string, userId string) (*model.ChannelList, *model.AppError) {
publicChannels, publicErr := s.performSearch(`
SELECT
Channels.*
FROM
Channels
JOIN
Channels c ON (c.Id = Channels.Id)
WHERE
c.TeamId = :TeamId
SEARCH_CLAUSE
AND c.DeleteAt != 0
AND c.Type != 'P'
ORDER BY c.DisplayName
LIMIT 100
`, term, map[string]interface{}{
"TeamId": teamId,
"UserId": userId,
})
privateChannels, privateErr := s.performSearch(`
SELECT
Channels.*
FROM
Channels
JOIN
Channels c ON (c.Id = Channels.Id)
WHERE
c.TeamId = :TeamId
SEARCH_CLAUSE
AND c.DeleteAt != 0
AND c.Type = 'P'
AND c.Id IN (SELECT ChannelId FROM ChannelMembers WHERE UserId = :UserId)
ORDER BY c.DisplayName
LIMIT 100
`, term, map[string]interface{}{
"TeamId": teamId,
"UserId": userId,
})
output := *publicChannels
output = append(output, *privateChannels...)
outputErr := publicErr
if privateErr != nil {
outputErr = privateErr
}
return &output, outputErr
}
func (s SqlChannelStore) SearchForUserInTeam(userId string, teamId string, term string, includeDeleted bool) (*model.ChannelList, *model.AppError) {
deleteFilter := "AND c.DeleteAt = 0"
if includeDeleted {

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

@@ -125,7 +125,7 @@ type ChannelStore interface {
GetByNames(team_id string, names []string, allowFromCache bool) ([]*model.Channel, *model.AppError)
GetByNameIncludeDeleted(team_id string, name string, allowFromCache bool) (*model.Channel, *model.AppError)
GetDeletedByName(team_id string, name string) (*model.Channel, *model.AppError)
GetDeleted(team_id string, offset int, limit int) (*model.ChannelList, *model.AppError)
GetDeleted(team_id string, offset int, limit int, userId string) (*model.ChannelList, *model.AppError)
GetChannels(teamId string, userId string, includeDeleted bool) (*model.ChannelList, *model.AppError)
GetAllChannels(page, perPage int, opts ChannelSearchOpts) (*model.ChannelListWithTeamData, *model.AppError)
GetAllChannelsCount(opts ChannelSearchOpts) (int64, *model.AppError)
@@ -170,6 +170,7 @@ type ChannelStore interface {
AutocompleteInTeamForSearch(teamId string, userId string, term string, includeDeleted bool) (*model.ChannelList, *model.AppError)
SearchAllChannels(term string, opts ChannelSearchOpts) (*model.ChannelListWithTeamData, *model.AppError)
SearchInTeam(teamId string, term string, includeDeleted bool) (*model.ChannelList, *model.AppError)
SearchArchivedInTeam(teamId string, term string, userId string) (*model.ChannelList, *model.AppError)
SearchForUserInTeam(userId string, teamId string, term string, includeDeleted bool) (*model.ChannelList, *model.AppError)
SearchMore(userId string, teamId string, term string) (*model.ChannelList, *model.AppError)
SearchGroupChannels(userId, term string) (*model.ChannelList, *model.AppError)

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

@@ -687,13 +687,15 @@ func testChannelStoreGetDeleted(t *testing.T, ss store.Store) {
o1.Name = "zz" + model.NewId() + "b"
o1.Type = model.CHANNEL_OPEN
userId := model.NewId()
_, err := ss.Channel().Save(&o1, -1)
require.Nil(t, err)
err = ss.Channel().Delete(o1.Id, model.GetMillis())
require.Nil(t, err, "channel should have been deleted")
list, err := ss.Channel().GetDeleted(o1.TeamId, 0, 100)
list, err := ss.Channel().GetDeleted(o1.TeamId, 0, 100, userId)
require.Nil(t, err, err)
require.Len(t, *list, 1, "wrong list")
require.Equal(t, o1.Name, (*list)[0].Name, "missing channel")
@@ -706,7 +708,7 @@ func testChannelStoreGetDeleted(t *testing.T, ss store.Store) {
_, err = ss.Channel().Save(&o2, -1)
require.Nil(t, err)
list, err = ss.Channel().GetDeleted(o1.TeamId, 0, 100)
list, err = ss.Channel().GetDeleted(o1.TeamId, 0, 100, userId)
require.Nil(t, err, err)
require.Len(t, *list, 1, "wrong list")
@@ -722,15 +724,15 @@ func testChannelStoreGetDeleted(t *testing.T, ss store.Store) {
err = ss.Channel().Delete(o3.Id, model.GetMillis())
require.Nil(t, err, "channel should have been deleted")
list, err = ss.Channel().GetDeleted(o1.TeamId, 0, 100)
list, err = ss.Channel().GetDeleted(o1.TeamId, 0, 100, userId)
require.Nil(t, err, err)
require.Len(t, *list, 2, "wrong list length")
list, err = ss.Channel().GetDeleted(o1.TeamId, 0, 1)
list, err = ss.Channel().GetDeleted(o1.TeamId, 0, 1, userId)
require.Nil(t, err, err)
require.Len(t, *list, 1, "wrong list length")
list, err = ss.Channel().GetDeleted(o1.TeamId, 1, 1)
list, err = ss.Channel().GetDeleted(o1.TeamId, 1, 1, userId)
require.Nil(t, err, err)
require.Len(t, *list, 1, "wrong list length")

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

@@ -647,7 +647,7 @@ func (_m *ChannelStore) GetChannelsByScheme(schemeId string, offset int, limit i
}
// GetDeleted provides a mock function with given fields: team_id, offset, limit
func (_m *ChannelStore) GetDeleted(team_id string, offset int, limit int) (*model.ChannelList, *model.AppError) {
func (_m *ChannelStore) GetDeleted(team_id string, offset int, limit int, userId string) (*model.ChannelList, *model.AppError) {
ret := _m.Called(team_id, offset, limit)
var r0 *model.ChannelList
@@ -1539,6 +1539,31 @@ func (_m *ChannelStore) SearchInTeam(teamId string, term string, includeDeleted
return r0, r1
}
// SearchArchivedInTeam provides a mock function with given fields: teamId, term, userId
func (_m *ChannelStore) SearchArchivedInTeam(teamId string, term string, userId string) (*model.ChannelList, *model.AppError) {
ret := _m.Called(teamId, term, userId)
var r0 *model.ChannelList
if rf, ok := ret.Get(0).(func(string, string, string) *model.ChannelList); ok {
r0 = rf(teamId, term, userId)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.ChannelList)
}
}
var r1 *model.AppError
if rf, ok := ret.Get(1).(func(string, string, string) *model.AppError); ok {
r1 = rf(teamId, term, userId)
} else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)
}
}
return r0, r1
}
// SearchMore provides a mock function with given fields: userId, teamId, term
func (_m *ChannelStore) SearchMore(userId string, teamId string, term string) (*model.ChannelList, *model.AppError) {
ret := _m.Called(userId, teamId, term)

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

@@ -904,10 +904,10 @@ func (s *TimerLayerChannelStore) GetChannelsByScheme(schemeId string, offset int
return resultVar0, resultVar1
}
func (s *TimerLayerChannelStore) GetDeleted(team_id string, offset int, limit int) (*model.ChannelList, *model.AppError) {
func (s *TimerLayerChannelStore) GetDeleted(team_id string, offset int, limit int, userId string) (*model.ChannelList, *model.AppError) {
start := timemodule.Now()
resultVar0, resultVar1 := s.ChannelStore.GetDeleted(team_id, offset, limit)
resultVar0, resultVar1 := s.ChannelStore.GetDeleted(team_id, offset, limit, userId)
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
if s.Root.Metrics != nil {