store: guests will only receive results of which channels they are in (#20295)

* store: guests will only receive results of which channels they are in

* api4/channel_test: add test case for guest accounts channel autocomplete

* apply to searchengine and also for AutocompleteInTeam

Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
Этот коммит содержится в:
Ibrahim Serdar Acikgoz
2022-06-01 09:18:59 +03:00
коммит произвёл GitHub
родитель cffe921e62
Коммит fe3816cc20
14 изменённых файлов: 204 добавлений и 116 удалений

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

@@ -1339,6 +1339,46 @@ func TestSearchChannels(t *testing.T) {
}
require.NotContains(t, channelNames, th.BasicChannel.Name)
})
t.Run("Guests only receive autocompletion for which accounts they are a member of", func(t *testing.T) {
th.App.Srv().SetLicense(model.NewTestLicense(""))
defer th.App.Srv().SetLicense(nil)
enableGuestAccounts := *th.App.Config().GuestAccountsSettings.Enable
defer func() {
th.App.UpdateConfig(func(cfg *model.Config) { cfg.GuestAccountsSettings.Enable = &enableGuestAccounts })
}()
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.GuestAccountsSettings.Enable = true })
guest := th.CreateUser()
_, appErr := th.SystemAdminClient.DemoteUserToGuest(guest.Id)
require.NoError(t, appErr)
_, resp, err := th.SystemAdminClient.AddTeamMember(th.BasicTeam.Id, guest.Id)
require.NoError(t, err)
CheckCreatedStatus(t, resp)
_, resp, err = client.Login(guest.Username, guest.Password)
require.NoError(t, err)
CheckOKStatus(t, resp)
search.Term = th.BasicChannel2.Name
channelList, _, err := client.SearchChannels(th.BasicTeam.Id, search)
require.NoError(t, err)
require.Empty(t, channelList)
_, resp, err = th.SystemAdminClient.AddChannelMember(th.BasicChannel2.Id, guest.Id)
require.NoError(t, err)
CheckCreatedStatus(t, resp)
search.Term = th.BasicChannel2.Name
channelList, _, err = client.SearchChannels(th.BasicTeam.Id, search)
require.NoError(t, err)
require.NotEmpty(t, channelList)
require.Equal(t, th.BasicChannel2.Id, channelList[0].Id)
})
}
func TestSearchArchivedChannels(t *testing.T) {

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

@@ -2781,7 +2781,12 @@ func (a *App) AutocompleteChannels(userID, term string) (model.ChannelListWithTe
includeDeleted := *a.Config().TeamSettings.ExperimentalViewArchivedChannels
term = strings.TrimSpace(term)
channelList, err := a.Srv().Store.Channel().Autocomplete(userID, term, includeDeleted)
user, appErr := a.GetUser(userID)
if appErr != nil {
return nil, appErr
}
channelList, err := a.Srv().Store.Channel().Autocomplete(userID, term, includeDeleted, user.IsGuest())
if err != nil {
return nil, model.NewAppError("AutocompleteChannels", "app.channel.search.app_error", nil, err.Error(), http.StatusInternalServerError)
}
@@ -2793,7 +2798,12 @@ func (a *App) AutocompleteChannelsForTeam(teamID, userID, term string) (model.Ch
includeDeleted := *a.Config().TeamSettings.ExperimentalViewArchivedChannels
term = strings.TrimSpace(term)
channelList, err := a.Srv().Store.Channel().AutocompleteInTeam(teamID, userID, term, includeDeleted)
user, appErr := a.GetUser(userID)
if appErr != nil {
return nil, appErr
}
channelList, err := a.Srv().Store.Channel().AutocompleteInTeam(teamID, userID, term, includeDeleted, user.IsGuest())
if err != nil {
return nil, model.NewAppError("AutocompleteChannels", "app.channel.search.app_error", nil, err.Error(), http.StatusInternalServerError)
}

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

@@ -314,7 +314,7 @@ func (b *BleveEngine) IndexChannel(channel *model.Channel, userIDs, teamMemberID
return nil
}
func (b *BleveEngine) SearchChannels(teamId, userID, term string) ([]string, *model.AppError) {
func (b *BleveEngine) SearchChannels(teamId, userID, term string, isGuest bool) ([]string, *model.AppError) {
// This query essentially boils down to (if teamID is passed):
// match teamID == <>
// AND
@@ -329,6 +329,13 @@ func (b *BleveEngine) SearchChannels(teamId, userID, term string) ([]string, *mo
// AND
// match (channelType != 'P' || (<> in userIDs && channelType == 'P'))
// (or if isGuest is true)
// <> in teamMemberIds
// AND
// match term == <>
// AND
// match (<> in userIDs)
queries := []query.Query{}
if teamId != "" {
teamIdQ := bleve.NewTermQuery(teamId)
@@ -340,22 +347,29 @@ func (b *BleveEngine) SearchChannels(teamId, userID, term string) ([]string, *mo
queries = append(queries, teamMemberQ)
}
boolNotPrivate := bleve.NewBooleanQuery()
privateQ := bleve.NewTermQuery(string(model.ChannelTypePrivate))
privateQ.SetField("Type")
boolNotPrivate.AddMustNot(privateQ)
if isGuest {
userQ := bleve.NewBooleanQuery()
userIDQ := bleve.NewTermQuery(userID)
userIDQ.SetField("UserIDs")
userQ.AddMust(userIDQ)
queries = append(queries, userIDQ)
} else {
boolNotPrivate := bleve.NewBooleanQuery()
privateQ := bleve.NewTermQuery(string(model.ChannelTypePrivate))
privateQ.SetField("Type")
boolNotPrivate.AddMustNot(privateQ)
userQ := bleve.NewBooleanQuery()
userIDQ := bleve.NewTermQuery(userID)
userIDQ.SetField("UserIDs")
userQ.AddMust(userIDQ)
userQ.AddMust(privateQ)
userQ := bleve.NewBooleanQuery()
userIDQ := bleve.NewTermQuery(userID)
userIDQ.SetField("UserIDs")
userQ.AddMust(userIDQ)
userQ.AddMust(privateQ)
channelTypeQ := bleve.NewDisjunctionQuery()
channelTypeQ.AddQuery(boolNotPrivate)
channelTypeQ.AddQuery(userQ) // userID && 'p'
queries = append(queries, channelTypeQ)
channelTypeQ := bleve.NewDisjunctionQuery()
channelTypeQ.AddQuery(boolNotPrivate)
channelTypeQ.AddQuery(userQ) // userID && 'p'
queries = append(queries, channelTypeQ)
}
if term != "" {
nameSuggestQ := bleve.NewPrefixQuery(strings.ToLower(term))

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

@@ -30,7 +30,7 @@ type SearchEngineInterface interface {
// IndexChannel indexes a given channel. The userIDs are only populated
// for private channels.
IndexChannel(channel *model.Channel, userIDs, teamMemberIDs []string) *model.AppError
SearchChannels(teamId, userID, term string) ([]string, *model.AppError)
SearchChannels(teamId, userID, term string, isGuest bool) ([]string, *model.AppError)
DeleteChannel(channel *model.Channel) *model.AppError
IndexUser(user *model.User, teamsIds, channelsIds []string) *model.AppError
SearchUsersInChannel(teamId, channelId string, restrictedToChannels []string, term string, options *model.UserSearchOptions) ([]string, []string, *model.AppError)

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

@@ -400,13 +400,13 @@ func (_m *SearchEngineInterface) RefreshIndexes() *model.AppError {
return r0
}
// SearchChannels provides a mock function with given fields: teamId, userID, term
func (_m *SearchEngineInterface) SearchChannels(teamId string, userID string, term string) ([]string, *model.AppError) {
ret := _m.Called(teamId, userID, term)
// SearchChannels provides a mock function with given fields: teamId, userID, term, isGuest
func (_m *SearchEngineInterface) SearchChannels(teamId string, userID string, term string, isGuest bool) ([]string, *model.AppError) {
ret := _m.Called(teamId, userID, term, isGuest)
var r0 []string
if rf, ok := ret.Get(0).(func(string, string, string) []string); ok {
r0 = rf(teamId, userID, term)
if rf, ok := ret.Get(0).(func(string, string, string, bool) []string); ok {
r0 = rf(teamId, userID, term, isGuest)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]string)
@@ -414,8 +414,8 @@ func (_m *SearchEngineInterface) SearchChannels(teamId string, userID string, te
}
var r1 *model.AppError
if rf, ok := ret.Get(1).(func(string, string, string) *model.AppError); ok {
r1 = rf(teamId, userID, term)
if rf, ok := ret.Get(1).(func(string, string, string, bool) *model.AppError); ok {
r1 = rf(teamId, userID, term, isGuest)
} else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)

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

@@ -570,7 +570,7 @@ func (s *OpenTracingLayerChannelStore) AnalyticsTypeCount(teamID string, channel
return result, err
}
func (s *OpenTracingLayerChannelStore) Autocomplete(userID string, term string, includeDeleted bool) (model.ChannelListWithTeamData, error) {
func (s *OpenTracingLayerChannelStore) Autocomplete(userID string, term string, includeDeleted bool, isGuest bool) (model.ChannelListWithTeamData, error) {
origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.Autocomplete")
s.Root.Store.SetContext(newCtx)
@@ -579,7 +579,7 @@ func (s *OpenTracingLayerChannelStore) Autocomplete(userID string, term string,
}()
defer span.Finish()
result, err := s.ChannelStore.Autocomplete(userID, term, includeDeleted)
result, err := s.ChannelStore.Autocomplete(userID, term, includeDeleted, isGuest)
if err != nil {
span.LogFields(spanlog.Error(err))
ext.Error.Set(span, true)
@@ -588,7 +588,7 @@ func (s *OpenTracingLayerChannelStore) Autocomplete(userID string, term string,
return result, err
}
func (s *OpenTracingLayerChannelStore) AutocompleteInTeam(teamID string, userID string, term string, includeDeleted bool) (model.ChannelList, error) {
func (s *OpenTracingLayerChannelStore) AutocompleteInTeam(teamID string, userID string, term string, includeDeleted bool, isGuest bool) (model.ChannelList, error) {
origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.AutocompleteInTeam")
s.Root.Store.SetContext(newCtx)
@@ -597,7 +597,7 @@ func (s *OpenTracingLayerChannelStore) AutocompleteInTeam(teamID string, userID
}()
defer span.Finish()
result, err := s.ChannelStore.AutocompleteInTeam(teamID, userID, term, includeDeleted)
result, err := s.ChannelStore.AutocompleteInTeam(teamID, userID, term, includeDeleted, isGuest)
if err != nil {
span.LogFields(spanlog.Error(err))
ext.Error.Set(span, true)

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

@@ -619,11 +619,11 @@ func (s *RetryLayerChannelStore) AnalyticsTypeCount(teamID string, channelType m
}
func (s *RetryLayerChannelStore) Autocomplete(userID string, term string, includeDeleted bool) (model.ChannelListWithTeamData, error) {
func (s *RetryLayerChannelStore) Autocomplete(userID string, term string, includeDeleted bool, isGuest bool) (model.ChannelListWithTeamData, error) {
tries := 0
for {
result, err := s.ChannelStore.Autocomplete(userID, term, includeDeleted)
result, err := s.ChannelStore.Autocomplete(userID, term, includeDeleted, isGuest)
if err == nil {
return result, nil
}
@@ -640,11 +640,11 @@ func (s *RetryLayerChannelStore) Autocomplete(userID string, term string, includ
}
func (s *RetryLayerChannelStore) AutocompleteInTeam(teamID string, userID string, term string, includeDeleted bool) (model.ChannelList, error) {
func (s *RetryLayerChannelStore) AutocompleteInTeam(teamID string, userID string, term string, includeDeleted bool, isGuest bool) (model.ChannelList, error) {
tries := 0
for {
result, err := s.ChannelStore.AutocompleteInTeam(teamID, userID, term, includeDeleted)
result, err := s.ChannelStore.AutocompleteInTeam(teamID, userID, term, includeDeleted, isGuest)
if err == nil {
return result, nil
}

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

@@ -161,14 +161,14 @@ func (c *SearchChannelStore) SaveDirectChannel(directchannel *model.Channel, mem
return channel, err
}
func (c *SearchChannelStore) Autocomplete(userID, term string, includeDeleted bool) (model.ChannelListWithTeamData, error) {
func (c *SearchChannelStore) Autocomplete(userID, term string, includeDeleted, isGuest bool) (model.ChannelListWithTeamData, error) {
var channelList model.ChannelListWithTeamData
var err error
allFailed := true
for _, engine := range c.rootStore.searchEngine.GetActiveEngines() {
if engine.IsAutocompletionEnabled() {
channelList, err = c.searchAutocompleteChannelsAllTeams(engine, userID, term, includeDeleted)
channelList, err = c.searchAutocompleteChannelsAllTeams(engine, userID, term, includeDeleted, isGuest)
if err != nil {
mlog.Warn("Encountered error on AutocompleteChannels through SearchEngine. Falling back to default autocompletion.", mlog.String("search_engine", engine.GetName()), mlog.Err(err))
continue
@@ -181,7 +181,7 @@ func (c *SearchChannelStore) Autocomplete(userID, term string, includeDeleted bo
if allFailed {
mlog.Debug("Using database search because no other search engine is available")
channelList, err = c.ChannelStore.Autocomplete(userID, term, includeDeleted)
channelList, err = c.ChannelStore.Autocomplete(userID, term, includeDeleted, isGuest)
if err != nil {
return nil, errors.Wrap(err, "Failed to autocomplete channels in team")
}
@@ -194,14 +194,14 @@ func (c *SearchChannelStore) Autocomplete(userID, term string, includeDeleted bo
return channelList, nil
}
func (c *SearchChannelStore) AutocompleteInTeam(teamID, userID, term string, includeDeleted bool) (model.ChannelList, error) {
func (c *SearchChannelStore) AutocompleteInTeam(teamID, userID, term string, includeDeleted, isGuest bool) (model.ChannelList, error) {
var channelList model.ChannelList
var err error
allFailed := true
for _, engine := range c.rootStore.searchEngine.GetActiveEngines() {
if engine.IsAutocompletionEnabled() {
channelList, err = c.searchAutocompleteChannels(engine, teamID, userID, term, includeDeleted)
channelList, err = c.searchAutocompleteChannels(engine, teamID, userID, term, includeDeleted, isGuest)
if err != nil {
mlog.Warn("Encountered error on AutocompleteChannels through SearchEngine. Falling back to default autocompletion.", mlog.String("search_engine", engine.GetName()), mlog.Err(err))
continue
@@ -214,7 +214,7 @@ func (c *SearchChannelStore) AutocompleteInTeam(teamID, userID, term string, inc
if allFailed {
mlog.Debug("Using database search because no other search engine is available")
channelList, err = c.ChannelStore.AutocompleteInTeam(teamID, userID, term, includeDeleted)
channelList, err = c.ChannelStore.AutocompleteInTeam(teamID, userID, term, includeDeleted, isGuest)
if err != nil {
return nil, errors.Wrap(err, "Failed to autocomplete channels in team")
}
@@ -227,8 +227,8 @@ func (c *SearchChannelStore) AutocompleteInTeam(teamID, userID, term string, inc
return channelList, nil
}
func (c *SearchChannelStore) searchAutocompleteChannels(engine searchengine.SearchEngineInterface, teamId, userID, term string, includeDeleted bool) (model.ChannelList, error) {
channelIds, err := engine.SearchChannels(teamId, userID, term)
func (c *SearchChannelStore) searchAutocompleteChannels(engine searchengine.SearchEngineInterface, teamId, userID, term string, includeDeleted, isGuest bool) (model.ChannelList, error) {
channelIds, err := engine.SearchChannels(teamId, userID, term, isGuest)
if err != nil {
return nil, err
}
@@ -245,8 +245,8 @@ func (c *SearchChannelStore) searchAutocompleteChannels(engine searchengine.Sear
return channelList, nil
}
func (c *SearchChannelStore) searchAutocompleteChannelsAllTeams(engine searchengine.SearchEngineInterface, userID, term string, includeDeleted bool) (model.ChannelListWithTeamData, error) {
channelIds, err := engine.SearchChannels("", userID, term)
func (c *SearchChannelStore) searchAutocompleteChannelsAllTeams(engine searchengine.SearchEngineInterface, userID, term string, includeDeleted, isGuest bool) (model.ChannelListWithTeamData, error) {
channelIds, err := engine.SearchChannels("", userID, term, isGuest)
if err != nil {
return nil, err
}

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

@@ -94,11 +94,11 @@ func testAutocompleteChannelByName(t *testing.T, th *SearchTestHelper) {
require.NoError(t, err)
defer th.deleteChannel(private)
res, err := th.Store.Channel().AutocompleteInTeam(th.Team.Id, th.User.Id, "channel-a", false)
res, err := th.Store.Channel().AutocompleteInTeam(th.Team.Id, th.User.Id, "channel-a", false, false)
require.NoError(t, err)
th.checkChannelIdsMatch(t, []string{th.ChannelBasic.Id, alternate.Id, private.Id}, res)
res2, err := th.Store.Channel().Autocomplete(th.User.Id, "channel-a", false)
res2, err := th.Store.Channel().Autocomplete(th.User.Id, "channel-a", false, false)
require.NoError(t, err)
th.checkChannelIdsMatchWithTeamData(t, []string{th.ChannelBasic.Id, alternate.Id, private.Id, th.ChannelAnotherTeam.Id}, res2)
}
@@ -107,7 +107,7 @@ func testAutocompleteChannelByNamePostgres(t *testing.T, th *SearchTestHelper) {
alternate, err := th.createChannel(th.Team.Id, "channel-alternate", "Channel Alternate", "Channel Alternate", model.ChannelTypeOpen, th.User, false)
require.NoError(t, err)
defer th.deleteChannel(alternate)
res, err := th.Store.Channel().AutocompleteInTeam(th.Team.Id, th.User.Id, "channel-a", false)
res, err := th.Store.Channel().AutocompleteInTeam(th.Team.Id, th.User.Id, "channel-a", false, false)
require.NoError(t, err)
th.checkChannelIdsMatch(t, []string{th.ChannelBasic.Id, th.ChannelPrivate.Id, alternate.Id}, res)
}
@@ -121,11 +121,11 @@ func testAutocompleteChannelByDisplayName(t *testing.T, th *SearchTestHelper) {
require.NoError(t, err)
defer th.deleteChannel(private)
res, err := th.Store.Channel().AutocompleteInTeam(th.Team.Id, th.User.Id, "ChannelA", false)
res, err := th.Store.Channel().AutocompleteInTeam(th.Team.Id, th.User.Id, "ChannelA", false, false)
require.NoError(t, err)
th.checkChannelIdsMatch(t, []string{th.ChannelBasic.Id, alternate.Id, private.Id}, res)
res2, err := th.Store.Channel().Autocomplete(th.User.Id, "ChannelA", false)
res2, err := th.Store.Channel().Autocomplete(th.User.Id, "ChannelA", false, false)
require.NoError(t, err)
th.checkChannelIdsMatchWithTeamData(t, []string{th.ChannelBasic.Id, alternate.Id, private.Id, th.ChannelAnotherTeam.Id}, res2)
}
@@ -134,7 +134,7 @@ func testAutocompleteChannelByNameSplittedWithDashChar(t *testing.T, th *SearchT
alternate, err := th.createChannel(th.Team.Id, "channel-alternate", "ChannelAlternate", "", model.ChannelTypeOpen, th.User, false)
require.NoError(t, err)
defer th.deleteChannel(alternate)
res, err := th.Store.Channel().AutocompleteInTeam(th.Team.Id, th.User.Id, "channel-a", false)
res, err := th.Store.Channel().AutocompleteInTeam(th.Team.Id, th.User.Id, "channel-a", false, false)
require.NoError(t, err)
th.checkChannelIdsMatch(t, []string{th.ChannelBasic.Id, alternate.Id}, res)
}
@@ -143,7 +143,7 @@ func testAutocompleteChannelByNameSplittedWithDashCharPostgres(t *testing.T, th
alternate, err := th.createChannel(th.Team.Id, "channel-alternate", "ChannelAlternate", "", model.ChannelTypeOpen, th.User, false)
require.NoError(t, err)
defer th.deleteChannel(alternate)
res, err := th.Store.Channel().AutocompleteInTeam(th.Team.Id, th.User.Id, "channel-a", false)
res, err := th.Store.Channel().AutocompleteInTeam(th.Team.Id, th.User.Id, "channel-a", false, false)
require.NoError(t, err)
th.checkChannelIdsMatch(t, []string{th.ChannelBasic.Id, th.ChannelPrivate.Id, alternate.Id}, res)
}
@@ -152,11 +152,11 @@ func testAutocompleteChannelByNameSplittedWithUnderscoreChar(t *testing.T, th *S
alternate, err := th.createChannel(th.Team.Id, "channel_alternate", "ChannelAlternate", "", model.ChannelTypeOpen, th.User, false)
require.NoError(t, err)
defer th.deleteChannel(alternate)
res, err := th.Store.Channel().AutocompleteInTeam(th.Team.Id, th.User.Id, "channel_a", false)
res, err := th.Store.Channel().AutocompleteInTeam(th.Team.Id, th.User.Id, "channel_a", false, false)
require.NoError(t, err)
th.checkChannelIdsMatch(t, []string{alternate.Id}, res)
res2, err := th.Store.Channel().Autocomplete(th.User.Id, "channel_a", false)
res2, err := th.Store.Channel().Autocomplete(th.User.Id, "channel_a", false, false)
require.NoError(t, err)
th.checkChannelIdsMatchWithTeamData(t, []string{alternate.Id}, res2)
}
@@ -166,7 +166,7 @@ func testAutocompleteChannelByDisplayNameSplittedByWhitespaces(t *testing.T, th
require.NoError(t, err)
defer th.deleteChannel(alternate)
res, err := th.Store.Channel().AutocompleteInTeam(th.Team.Id, th.User.Id, "Channel A", false)
res, err := th.Store.Channel().AutocompleteInTeam(th.Team.Id, th.User.Id, "Channel A", false, false)
require.NoError(t, err)
th.checkChannelIdsMatch(t, []string{alternate.Id}, res)
}
@@ -177,7 +177,7 @@ func testAutocompleteAllChannelsIfTermIsEmpty(t *testing.T, th *SearchTestHelper
require.NoError(t, err)
defer th.deleteChannel(alternate)
defer th.deleteChannel(other)
res, err := th.Store.Channel().AutocompleteInTeam(th.Team.Id, th.User.Id, "", false)
res, err := th.Store.Channel().AutocompleteInTeam(th.Team.Id, th.User.Id, "", false, false)
require.NoError(t, err)
th.checkChannelIdsMatch(t, []string{th.ChannelBasic.Id, th.ChannelPrivate.Id, alternate.Id, other.Id}, res)
}
@@ -186,17 +186,17 @@ func testSearchChannelsInCaseInsensitiveManner(t *testing.T, th *SearchTestHelpe
alternate, err := th.createChannel(th.Team.Id, "channel-alternate", "ChannelAlternate", "", model.ChannelTypeOpen, th.User, false)
require.NoError(t, err)
defer th.deleteChannel(alternate)
res, err := th.Store.Channel().AutocompleteInTeam(th.Team.Id, th.User.Id, "channela", false)
res, err := th.Store.Channel().AutocompleteInTeam(th.Team.Id, th.User.Id, "channela", false, false)
require.NoError(t, err)
th.checkChannelIdsMatch(t, []string{th.ChannelBasic.Id, alternate.Id}, res)
res, err = th.Store.Channel().AutocompleteInTeam(th.Team.Id, th.User.Id, "ChAnNeL-a", false)
res, err = th.Store.Channel().AutocompleteInTeam(th.Team.Id, th.User.Id, "ChAnNeL-a", false, false)
require.NoError(t, err)
th.checkChannelIdsMatch(t, []string{th.ChannelBasic.Id, alternate.Id}, res)
res2, err := th.Store.Channel().Autocomplete(th.User.Id, "channela", false)
res2, err := th.Store.Channel().Autocomplete(th.User.Id, "channela", false, false)
require.NoError(t, err)
th.checkChannelIdsMatchWithTeamData(t, []string{th.ChannelAnotherTeam.Id, th.ChannelBasic.Id, alternate.Id}, res2)
res2, err = th.Store.Channel().Autocomplete(th.User.Id, "ChAnNeL-a", false)
res2, err = th.Store.Channel().Autocomplete(th.User.Id, "ChAnNeL-a", false, false)
require.NoError(t, err)
th.checkChannelIdsMatchWithTeamData(t, []string{th.ChannelAnotherTeam.Id, th.ChannelBasic.Id, alternate.Id}, res2)
}
@@ -205,10 +205,10 @@ func testSearchChannelsInCaseInsensitiveMannerPostgres(t *testing.T, th *SearchT
alternate, err := th.createChannel(th.Team.Id, "channel-alternate", "ChannelAlternate", "", model.ChannelTypeOpen, th.User, false)
require.NoError(t, err)
defer th.deleteChannel(alternate)
res, err := th.Store.Channel().AutocompleteInTeam(th.Team.Id, th.User.Id, "channela", false)
res, err := th.Store.Channel().AutocompleteInTeam(th.Team.Id, th.User.Id, "channela", false, false)
require.NoError(t, err)
th.checkChannelIdsMatch(t, []string{th.ChannelBasic.Id, alternate.Id}, res)
res, err = th.Store.Channel().AutocompleteInTeam(th.Team.Id, th.User.Id, "ChAnNeL-a", false)
res, err = th.Store.Channel().AutocompleteInTeam(th.Team.Id, th.User.Id, "ChAnNeL-a", false, false)
require.NoError(t, err)
th.checkChannelIdsMatch(t, []string{th.ChannelBasic.Id, th.ChannelPrivate.Id, alternate.Id}, res)
}
@@ -217,17 +217,17 @@ func testSearchShouldSupportHavingHyphenAsLastCharacter(t *testing.T, th *Search
alternate, err := th.createChannel(th.Team.Id, "channel-alternate", "ChannelAlternate", "", model.ChannelTypeOpen, th.User, false)
require.NoError(t, err)
defer th.deleteChannel(alternate)
res, err := th.Store.Channel().AutocompleteInTeam(th.Team.Id, th.User.Id, "channel-", false)
res, err := th.Store.Channel().AutocompleteInTeam(th.Team.Id, th.User.Id, "channel-", false, false)
require.NoError(t, err)
th.checkChannelIdsMatch(t, []string{th.ChannelBasic.Id, th.ChannelPrivate.Id, alternate.Id}, res)
res2, err := th.Store.Channel().Autocomplete(th.User.Id, "channel-", false)
res2, err := th.Store.Channel().Autocomplete(th.User.Id, "channel-", false, false)
require.NoError(t, err)
th.checkChannelIdsMatchWithTeamData(t, []string{th.ChannelAnotherTeam.Id, th.ChannelBasic.Id, th.ChannelPrivate.Id, alternate.Id}, res2)
}
func testSearchShouldSupportAutocompleteWithArchivedChannels(t *testing.T, th *SearchTestHelper) {
res, err := th.Store.Channel().AutocompleteInTeam(th.Team.Id, th.User.Id, "channel-", true)
res, err := th.Store.Channel().AutocompleteInTeam(th.Team.Id, th.User.Id, "channel-", true, false)
require.NoError(t, err)
th.checkChannelIdsMatch(t, []string{th.ChannelBasic.Id, th.ChannelPrivate.Id, th.ChannelDeleted.Id}, res)
}

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

@@ -2921,7 +2921,7 @@ func (s SqlChannelStore) GetTeamMembersForChannel(channelID string) ([]string, e
return teamMemberIDs, nil
}
func (s SqlChannelStore) Autocomplete(userID, term string, includeDeleted bool) (model.ChannelListWithTeamData, error) {
func (s SqlChannelStore) Autocomplete(userID, term string, includeDeleted, isGuest bool) (model.ChannelListWithTeamData, error) {
query := s.getQueryBuilder().Select("c.*",
"t.DisplayName AS TeamDisplayName",
"t.Name AS TeamName",
@@ -2931,15 +2931,6 @@ func (s SqlChannelStore) Autocomplete(userID, term string, includeDeleted bool)
sq.Expr("c.TeamId = t.id"),
sq.Expr("t.id = tm.TeamId"),
sq.Eq{"tm.UserId": userID},
sq.Or{
sq.NotEq{"c.Type": model.ChannelTypePrivate},
sq.And{
sq.Eq{"c.Type": model.ChannelTypePrivate},
sq.Expr("c.Id IN (?)", sq.Select("ChannelId").
From("ChannelMembers").
Where(sq.Eq{"UserId": userID})),
},
},
}).
OrderBy("c.DisplayName")
@@ -2949,6 +2940,23 @@ func (s SqlChannelStore) Autocomplete(userID, term string, includeDeleted bool)
sq.Eq{"tm.DeleteAt": 0},
})
}
if isGuest {
query = query.Where(sq.Expr("c.Id IN (?)", sq.Select("ChannelId").
From("ChannelMembers").
Where(sq.Eq{"UserId": userID})))
} else {
query = query.Where(sq.Or{
sq.NotEq{"c.Type": model.ChannelTypePrivate},
sq.And{
sq.Eq{"c.Type": model.ChannelTypePrivate},
sq.Expr("c.Id IN (?)", sq.Select("ChannelId").
From("ChannelMembers").
Where(sq.Eq{"UserId": userID})),
},
})
}
searchClause := s.searchClause(term)
if searchClause != nil {
query = query.Where(searchClause)
@@ -2967,21 +2975,10 @@ func (s SqlChannelStore) Autocomplete(userID, term string, includeDeleted bool)
return channels, nil
}
func (s SqlChannelStore) AutocompleteInTeam(teamID, userID, term string, includeDeleted bool) (model.ChannelList, error) {
func (s SqlChannelStore) AutocompleteInTeam(teamID, userID, term string, includeDeleted, isGuest bool) (model.ChannelList, error) {
query := s.getQueryBuilder().Select("*").
From("Channels c").
Where(sq.And{
sq.Eq{"c.TeamId": teamID},
sq.Or{
sq.NotEq{"c.Type": model.ChannelTypePrivate},
sq.And{
sq.Eq{"c.Type": model.ChannelTypePrivate},
sq.Expr("c.Id IN (?)", sq.Select("ChannelId").
From("ChannelMembers").
Where(sq.Eq{"UserId": userID})),
},
},
}).
Where(sq.Eq{"c.TeamId": teamID}).
OrderBy("c.DisplayName").
Limit(model.ChannelSearchDefaultLimit)
@@ -2989,6 +2986,22 @@ func (s SqlChannelStore) AutocompleteInTeam(teamID, userID, term string, include
query = query.Where(sq.Eq{"c.DeleteAt": 0})
}
if isGuest {
query = query.Where(sq.Expr("c.Id IN (?)", sq.Select("ChannelId").
From("ChannelMembers").
Where(sq.Eq{"UserId": userID})))
} else {
query = query.Where(sq.Or{
sq.NotEq{"c.Type": model.ChannelTypePrivate},
sq.And{
sq.Eq{"c.Type": model.ChannelTypePrivate},
sq.Expr("c.Id IN (?)", sq.Select("ChannelId").
From("ChannelMembers").
Where(sq.Eq{"UserId": userID})),
},
})
}
searchClause := s.searchClause(term)
if searchClause != nil {
query = query.Where(searchClause)

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

@@ -235,8 +235,8 @@ type ChannelStore interface {
GetTeamMembersForChannel(channelID string) ([]string, error)
GetMembersForUserWithPagination(userID string, page, perPage int) (model.ChannelMembersWithTeamData, error)
GetMembersForUserWithCursor(userID, teamID string, opts *ChannelMemberGraphQLSearchOpts) (model.ChannelMembers, error)
Autocomplete(userID, term string, includeDeleted bool) (model.ChannelListWithTeamData, error)
AutocompleteInTeam(teamID, userID, term string, includeDeleted bool) (model.ChannelList, error)
Autocomplete(userID, term string, includeDeleted, isGuest bool) (model.ChannelListWithTeamData, error)
AutocompleteInTeam(teamID, userID, term string, includeDeleted, isGuest bool) (model.ChannelList, error)
AutocompleteInTeamForSearch(teamID string, userID string, term string, includeDeleted bool) (model.ChannelList, error)
SearchAllChannels(term string, opts ChannelSearchOpts) (model.ChannelListWithTeamData, int64, error)
SearchInTeam(teamID string, term string, includeDeleted bool) (model.ChannelList, error)

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

@@ -5899,7 +5899,7 @@ func testChannelStoreSearchInTeam(t *testing.T, ss store.Store) {
for _, testCase := range testCases {
t.Run("AutoCompleteInTeam/"+testCase.Description, func(t *testing.T) {
channels, err := ss.Channel().AutocompleteInTeam(testCase.TeamID, testCase.UserID, testCase.Term, testCase.IncludeDeleted)
channels, err := ss.Channel().AutocompleteInTeam(testCase.TeamID, testCase.UserID, testCase.Term, testCase.IncludeDeleted, false)
require.NoError(t, err)
sort.Sort(ByChannelDisplayName(channels))
require.Equal(t, testCase.ExpectedResults, channels)
@@ -5946,6 +5946,15 @@ func testAutocomplete(t *testing.T, ss store.Store) {
_, err = ss.Channel().Save(&o2, -1)
require.NoError(t, err)
o6 := model.Channel{
TeamId: teamID,
DisplayName: "ChannelA3",
Name: NewTestId(),
Type: model.ChannelTypeOpen,
}
_, err = ss.Channel().Save(&o6, -1)
require.NoError(t, err)
m1 := model.ChannelMember{
ChannelId: o1.Id,
UserId: model.NewId(),
@@ -6063,20 +6072,22 @@ func testAutocomplete(t *testing.T, ss store.Store) {
UserID string
Term string
IncludeDeleted bool
IsGuest bool
ExpectedChannelIds []string
ExpectedTeamNames []string
}{
{"user 1, Channel A", m1.UserId, "ChannelA", false, []string{o1.Id, o2.Id}, []string{t1.Name, t2.Name}},
{"user 1, Channel B", m1.UserId, "ChannelB", false, []string{o4.Id}, []string{t2.Name}},
{"user 2, Channel A", m3.UserId, "ChannelA", false, []string{o3.Id, o1.Id, o2.Id}, []string{t2.Name, t1.Name, t1.Name}},
{"user 2, Channel B", m3.UserId, "ChannelB", false, nil, nil},
{"user 1, empty string", m1.UserId, "", false, []string{o1.Id, o2.Id, o4.Id}, []string{t1.Name, t2.Name, t2.Name}},
{"user 2, empty string", m3.UserId, "", false, []string{o1.Id, o2.Id, o3.Id}, []string{t1.Name, t2.Name, t1.Name}},
{"user 1, Channel A", m1.UserId, "ChannelA", false, false, []string{o1.Id, o2.Id, o6.Id}, []string{t1.Name, t2.Name, t1.Name}},
{"user 1, Channel B", m1.UserId, "ChannelB", false, false, []string{o4.Id}, []string{t2.Name}},
{"user 2, Channel A", m3.UserId, "ChannelA", false, false, []string{o3.Id, o1.Id, o2.Id, o6.Id}, []string{t2.Name, t1.Name, t1.Name, t1.Name}},
{"user 2 guest, Channel A", m3.UserId, "ChannelA", false, true, []string{o2.Id, o3.Id}, []string{t2.Name, t1.Name}},
{"user 2, Channel B", m3.UserId, "ChannelB", false, false, nil, nil},
{"user 1, empty string", m1.UserId, "", false, false, []string{o1.Id, o2.Id, o4.Id, o6.Id}, []string{t1.Name, t2.Name, t2.Name, t1.Name}},
{"user 2, empty string", m3.UserId, "", false, false, []string{o1.Id, o2.Id, o3.Id, o6.Id}, []string{t1.Name, t2.Name, t1.Name, t1.Name}},
}
for _, testCase := range testCases {
t.Run("Autocomplete/"+testCase.Description, func(t *testing.T) {
channels, err := ss.Channel().Autocomplete(testCase.UserID, testCase.Term, testCase.IncludeDeleted)
channels, err := ss.Channel().Autocomplete(testCase.UserID, testCase.Term, testCase.IncludeDeleted, testCase.IsGuest)
require.NoError(t, err)
var gotChannelIds []string
var gotTeamNames []string
@@ -6084,8 +6095,8 @@ func testAutocomplete(t *testing.T, ss store.Store) {
gotChannelIds = append(gotChannelIds, ch.Id)
gotTeamNames = append(gotTeamNames, ch.TeamName)
}
require.ElementsMatch(t, testCase.ExpectedChannelIds, gotChannelIds)
require.ElementsMatch(t, testCase.ExpectedTeamNames, gotTeamNames)
require.ElementsMatch(t, testCase.ExpectedChannelIds, gotChannelIds, "channels IDs are not as expected")
require.ElementsMatch(t, testCase.ExpectedTeamNames, gotTeamNames, "team names are not as expected")
})
}
}

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

@@ -60,13 +60,13 @@ func (_m *ChannelStore) AnalyticsTypeCount(teamID string, channelType model.Chan
return r0, r1
}
// Autocomplete provides a mock function with given fields: userID, term, includeDeleted
func (_m *ChannelStore) Autocomplete(userID string, term string, includeDeleted bool) (model.ChannelListWithTeamData, error) {
ret := _m.Called(userID, term, includeDeleted)
// Autocomplete provides a mock function with given fields: userID, term, includeDeleted, isGuest
func (_m *ChannelStore) Autocomplete(userID string, term string, includeDeleted bool, isGuest bool) (model.ChannelListWithTeamData, error) {
ret := _m.Called(userID, term, includeDeleted, isGuest)
var r0 model.ChannelListWithTeamData
if rf, ok := ret.Get(0).(func(string, string, bool) model.ChannelListWithTeamData); ok {
r0 = rf(userID, term, includeDeleted)
if rf, ok := ret.Get(0).(func(string, string, bool, bool) model.ChannelListWithTeamData); ok {
r0 = rf(userID, term, includeDeleted, isGuest)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(model.ChannelListWithTeamData)
@@ -74,8 +74,8 @@ func (_m *ChannelStore) Autocomplete(userID string, term string, includeDeleted
}
var r1 error
if rf, ok := ret.Get(1).(func(string, string, bool) error); ok {
r1 = rf(userID, term, includeDeleted)
if rf, ok := ret.Get(1).(func(string, string, bool, bool) error); ok {
r1 = rf(userID, term, includeDeleted, isGuest)
} else {
r1 = ret.Error(1)
}
@@ -83,13 +83,13 @@ func (_m *ChannelStore) Autocomplete(userID string, term string, includeDeleted
return r0, r1
}
// AutocompleteInTeam provides a mock function with given fields: teamID, userID, term, includeDeleted
func (_m *ChannelStore) AutocompleteInTeam(teamID string, userID string, term string, includeDeleted bool) (model.ChannelList, error) {
ret := _m.Called(teamID, userID, term, includeDeleted)
// AutocompleteInTeam provides a mock function with given fields: teamID, userID, term, includeDeleted, isGuest
func (_m *ChannelStore) AutocompleteInTeam(teamID string, userID string, term string, includeDeleted bool, isGuest bool) (model.ChannelList, error) {
ret := _m.Called(teamID, userID, term, includeDeleted, isGuest)
var r0 model.ChannelList
if rf, ok := ret.Get(0).(func(string, string, string, bool) model.ChannelList); ok {
r0 = rf(teamID, userID, term, includeDeleted)
if rf, ok := ret.Get(0).(func(string, string, string, bool, bool) model.ChannelList); ok {
r0 = rf(teamID, userID, term, includeDeleted, isGuest)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(model.ChannelList)
@@ -97,8 +97,8 @@ func (_m *ChannelStore) AutocompleteInTeam(teamID string, userID string, term st
}
var r1 error
if rf, ok := ret.Get(1).(func(string, string, string, bool) error); ok {
r1 = rf(teamID, userID, term, includeDeleted)
if rf, ok := ret.Get(1).(func(string, string, string, bool, bool) error); ok {
r1 = rf(teamID, userID, term, includeDeleted, isGuest)
} else {
r1 = ret.Error(1)
}

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

@@ -550,10 +550,10 @@ func (s *TimerLayerChannelStore) AnalyticsTypeCount(teamID string, channelType m
return result, err
}
func (s *TimerLayerChannelStore) Autocomplete(userID string, term string, includeDeleted bool) (model.ChannelListWithTeamData, error) {
func (s *TimerLayerChannelStore) Autocomplete(userID string, term string, includeDeleted bool, isGuest bool) (model.ChannelListWithTeamData, error) {
start := timemodule.Now()
result, err := s.ChannelStore.Autocomplete(userID, term, includeDeleted)
result, err := s.ChannelStore.Autocomplete(userID, term, includeDeleted, isGuest)
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
if s.Root.Metrics != nil {
@@ -566,10 +566,10 @@ func (s *TimerLayerChannelStore) Autocomplete(userID string, term string, includ
return result, err
}
func (s *TimerLayerChannelStore) AutocompleteInTeam(teamID string, userID string, term string, includeDeleted bool) (model.ChannelList, error) {
func (s *TimerLayerChannelStore) AutocompleteInTeam(teamID string, userID string, term string, includeDeleted bool, isGuest bool) (model.ChannelList, error) {
start := timemodule.Now()
result, err := s.ChannelStore.AutocompleteInTeam(teamID, userID, term, includeDeleted)
result, err := s.ChannelStore.AutocompleteInTeam(teamID, userID, term, includeDeleted, isGuest)
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
if s.Root.Metrics != nil {