[MM-17194] Add search channels for user in case the user doesn't have the list channels permission (#11706)

* [MM-17194] Add search channels for user in case the user doesn't have the list channels permission

* Add tests for the API layer and control the case of a user not being a team member

* Remove unnecessary empty line
Этот коммит содержится в:
Miguel de la Cruz
2019-07-29 09:35:32 +02:00
коммит произвёл Jesús Espino
родитель 1fa505c833
Коммит 8858b15e7e
8 изменённых файлов: 271 добавлений и 5 удалений

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

@@ -2121,6 +2121,35 @@ func (s SqlChannelStore) SearchInTeam(teamId string, term string, includeDeleted
})
}
func (s SqlChannelStore) SearchForUserInTeam(userId string, teamId string, term string, includeDeleted bool) (*model.ChannelList, *model.AppError) {
deleteFilter := "AND c.DeleteAt = 0"
if includeDeleted {
deleteFilter = ""
}
return s.performSearch(`
SELECT
Channels.*
FROM
Channels
JOIN
PublicChannels c ON (c.Id = Channels.Id)
JOIN
ChannelMembers cm ON (c.Id = cm.ChannelId)
WHERE
c.TeamId = :TeamId
AND
cm.UserId = :UserId
`+deleteFilter+`
SEARCH_CLAUSE
ORDER BY c.DisplayName
LIMIT 100
`, term, map[string]interface{}{
"TeamId": teamId,
"UserId": userId,
})
}
func (s SqlChannelStore) SearchAllChannels(term string, opts store.ChannelSearchOpts) (*model.ChannelListWithTeamData, *model.AppError) {
query := s.getQueryBuilder().
Select("c.*, t.DisplayName AS TeamDisplayName, t.Name AS TeamName, t.UpdateAt as TeamUpdateAt").

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

@@ -188,6 +188,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)
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)
GetMembersByIds(channelId string, userIds []string) (*model.ChannelMembers, *model.AppError)

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

@@ -68,6 +68,7 @@ func TestChannelStore(t *testing.T, ss store.Store, s SqlSupplier) {
t.Run("GetGuestCount", func(t *testing.T) { testGetGuestCount(t, ss) })
t.Run("SearchMore", func(t *testing.T) { testChannelStoreSearchMore(t, ss) })
t.Run("SearchInTeam", func(t *testing.T) { testChannelStoreSearchInTeam(t, ss) })
t.Run("SearchForUserInTeam", func(t *testing.T) { testChannelStoreSearchForUserInTeam(t, ss) })
t.Run("SearchAllChannels", func(t *testing.T) { testChannelStoreSearchAllChannels(t, ss) })
t.Run("AutocompleteInTeamForSearch", func(t *testing.T) { testChannelStoreAutocompleteInTeamForSearch(t, ss, s) })
t.Run("GetMembersByIds", func(t *testing.T) { testChannelStoreGetMembersByIds(t, ss) })
@@ -2568,6 +2569,112 @@ func testChannelStoreSearchInTeam(t *testing.T, ss store.Store) {
}
}
func testChannelStoreSearchForUserInTeam(t *testing.T, ss store.Store) {
userId := model.NewId()
teamId := model.NewId()
otherTeamId := model.NewId()
// create 4 channels for the same team and one for other team
o1 := model.Channel{
TeamId: teamId,
DisplayName: "test-dev-1",
Name: "zz" + model.NewId() + "b",
Type: model.CHANNEL_OPEN,
}
_, err := ss.Channel().Save(&o1, -1)
require.Nil(t, err)
o2 := model.Channel{
TeamId: teamId,
DisplayName: "test-dev-2",
Name: "zz" + model.NewId() + "b",
Type: model.CHANNEL_OPEN,
}
_, err = ss.Channel().Save(&o2, -1)
require.Nil(t, err)
o3 := model.Channel{
TeamId: teamId,
DisplayName: "dev-3",
Name: "zz" + model.NewId() + "b",
Type: model.CHANNEL_OPEN,
}
_, err = ss.Channel().Save(&o3, -1)
require.Nil(t, err)
o4 := model.Channel{
TeamId: teamId,
DisplayName: "dev-4",
Name: "zz" + model.NewId() + "b",
Type: model.CHANNEL_OPEN,
}
_, err = ss.Channel().Save(&o4, -1)
require.Nil(t, err)
o5 := model.Channel{
TeamId: otherTeamId,
DisplayName: "other-team-dev-5",
Name: "zz" + model.NewId() + "b",
Type: model.CHANNEL_OPEN,
}
_, err = ss.Channel().Save(&o5, -1)
require.Nil(t, err)
// add the user to the first 3 channels and the other team channel
for _, c := range []model.Channel{o1, o2, o3, o5} {
_, err = ss.Channel().SaveMember(&model.ChannelMember{
ChannelId: c.Id,
UserId: userId,
NotifyProps: model.GetDefaultChannelNotifyProps(),
})
require.Nil(t, err)
}
searchAndCheck := func(t *testing.T, term string, includeDeleted bool, expectedDisplayNames []string) {
res, searchErr := ss.Channel().SearchForUserInTeam(userId, teamId, term, includeDeleted)
require.Nil(t, searchErr)
require.Len(t, *res, len(expectedDisplayNames))
resultDisplayNames := []string{}
for _, c := range *res {
resultDisplayNames = append(resultDisplayNames, c.DisplayName)
}
require.ElementsMatch(t, expectedDisplayNames, resultDisplayNames)
}
t.Run("Search for test, get channels 1 and 2", func(t *testing.T) {
searchAndCheck(t, "test", false, []string{o1.DisplayName, o2.DisplayName})
})
t.Run("Search for dev, get channels 1, 2 and 3", func(t *testing.T) {
searchAndCheck(t, "dev", false, []string{o1.DisplayName, o2.DisplayName, o3.DisplayName})
})
t.Run("After adding user to channel 4, search for dev, get channels 1, 2, 3 and 4", func(t *testing.T) {
_, err = ss.Channel().SaveMember(&model.ChannelMember{
ChannelId: o4.Id,
UserId: userId,
NotifyProps: model.GetDefaultChannelNotifyProps(),
})
require.Nil(t, err)
searchAndCheck(t, "dev", false, []string{o1.DisplayName, o2.DisplayName, o3.DisplayName, o4.DisplayName})
})
t.Run("Mark channel 1 as deleted, search for dev, get channels 2, 3 and 4", func(t *testing.T) {
o1.DeleteAt = model.GetMillis()
o1.UpdateAt = o1.DeleteAt
err = ss.Channel().Delete(o1.Id, o1.DeleteAt)
require.Nil(t, err)
searchAndCheck(t, "dev", false, []string{o2.DisplayName, o3.DisplayName, o4.DisplayName})
})
t.Run("With includeDeleted, search for dev, get channels 1, 2, 3 and 4", func(t *testing.T) {
searchAndCheck(t, "dev", true, []string{o1.DisplayName, o2.DisplayName, o3.DisplayName, o4.DisplayName})
})
}
func testChannelStoreSearchAllChannels(t *testing.T, ss store.Store) {
cleanupChannels(t, ss)

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

@@ -1420,6 +1420,31 @@ func (_m *ChannelStore) SearchAllChannels(term string, opts store.ChannelSearchO
return r0, r1
}
// SearchForUserInTeam provides a mock function with given fields: userId, teamId, term, includeDeleted
func (_m *ChannelStore) SearchForUserInTeam(userId string, teamId string, term string, includeDeleted bool) (*model.ChannelList, *model.AppError) {
ret := _m.Called(userId, teamId, term, includeDeleted)
var r0 *model.ChannelList
if rf, ok := ret.Get(0).(func(string, string, string, bool) *model.ChannelList); ok {
r0 = rf(userId, teamId, term, includeDeleted)
} 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, bool) *model.AppError); ok {
r1 = rf(userId, teamId, term, includeDeleted)
} else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)
}
}
return r0, r1
}
// SearchGroupChannels provides a mock function with given fields: userId, term
func (_m *ChannelStore) SearchGroupChannels(userId string, term string) (*model.ChannelList, *model.AppError) {
ret := _m.Called(userId, term)