From 715097cc76510a3d78ba83e8544ee7c956ed26e9 Mon Sep 17 00:00:00 2001 From: Jesse Hallam Date: Wed, 17 Oct 2018 11:24:12 -0400 Subject: MM-12234: configurable limit to user autocomplete and search matches (#9499) * unit test cleanup * allow limiting user search results * clean up test users before starting * model UserSearchOptions to simplify parameters --- store/sqlstore/user_store.go | 102 ++++++++++++++++++++++++++----------------- 1 file changed, 61 insertions(+), 41 deletions(-) (limited to 'store/sqlstore/user_store.go') diff --git a/store/sqlstore/user_store.go b/store/sqlstore/user_store.go index f0839c3b7..0e70a87d9 100644 --- a/store/sqlstore/user_store.go +++ b/store/sqlstore/user_store.go @@ -970,12 +970,11 @@ func (us SqlUserStore) GetAnyUnreadPostCountForChannel(userId string, channelId }) } -func (us SqlUserStore) Search(teamId string, term string, options map[string]bool) store.StoreChannel { +func (us SqlUserStore) Search(teamId string, term string, options *model.UserSearchOptions) store.StoreChannel { return store.Do(func(result *store.StoreResult) { searchQuery := "" if teamId == "" { - // Id != '' is added because both SEARCH_CLAUSE and INACTIVE_CLAUSE start with an AND searchQuery = ` SELECT @@ -986,8 +985,8 @@ func (us SqlUserStore) Search(teamId string, term string, options map[string]boo Id != '' SEARCH_CLAUSE INACTIVE_CLAUSE - ORDER BY Username ASC - LIMIT 100` + ORDER BY Username ASC + LIMIT :Limit` } else { searchQuery = ` SELECT @@ -1000,16 +999,19 @@ func (us SqlUserStore) Search(teamId string, term string, options map[string]boo AND TeamMembers.DeleteAt = 0 SEARCH_CLAUSE INACTIVE_CLAUSE - ORDER BY Users.Username ASC - LIMIT 100` + ORDER BY Users.Username ASC + LIMIT :Limit` } - *result = us.performSearch(searchQuery, term, options, map[string]interface{}{"TeamId": teamId}) + *result = us.performSearch(searchQuery, term, options, map[string]interface{}{ + "TeamId": teamId, + "Limit": options.Limit, + }) }) } -func (us SqlUserStore) SearchWithoutTeam(term string, options map[string]bool) store.StoreChannel { +func (us SqlUserStore) SearchWithoutTeam(term string, options *model.UserSearchOptions) store.StoreChannel { return store.Do(func(result *store.StoreResult) { searchQuery := ` SELECT @@ -1027,14 +1029,16 @@ func (us SqlUserStore) SearchWithoutTeam(term string, options map[string]bool) s SEARCH_CLAUSE INACTIVE_CLAUSE ORDER BY Username ASC - LIMIT 100` + LIMIT :Limit` - *result = us.performSearch(searchQuery, term, options, map[string]interface{}{}) + *result = us.performSearch(searchQuery, term, options, map[string]interface{}{ + "Limit": options.Limit, + }) }) } -func (us SqlUserStore) SearchNotInTeam(notInTeamId string, term string, options map[string]bool) store.StoreChannel { +func (us SqlUserStore) SearchNotInTeam(notInTeamId string, term string, options *model.UserSearchOptions) store.StoreChannel { return store.Do(func(result *store.StoreResult) { searchQuery := ` SELECT @@ -1048,14 +1052,17 @@ func (us SqlUserStore) SearchNotInTeam(notInTeamId string, term string, options SEARCH_CLAUSE INACTIVE_CLAUSE ORDER BY Users.Username ASC - LIMIT 100` + LIMIT :Limit` - *result = us.performSearch(searchQuery, term, options, map[string]interface{}{"NotInTeamId": notInTeamId}) + *result = us.performSearch(searchQuery, term, options, map[string]interface{}{ + "NotInTeamId": notInTeamId, + "Limit": options.Limit, + }) }) } -func (us SqlUserStore) SearchNotInChannel(teamId string, channelId string, term string, options map[string]bool) store.StoreChannel { +func (us SqlUserStore) SearchNotInChannel(teamId string, channelId string, term string, options *model.UserSearchOptions) store.StoreChannel { return store.Do(func(result *store.StoreResult) { searchQuery := "" if teamId == "" { @@ -1071,7 +1078,7 @@ func (us SqlUserStore) SearchNotInChannel(teamId string, channelId string, term SEARCH_CLAUSE INACTIVE_CLAUSE ORDER BY Users.Username ASC - LIMIT 100` + LIMIT :Limit` } else { searchQuery = ` SELECT @@ -1089,30 +1096,37 @@ func (us SqlUserStore) SearchNotInChannel(teamId string, channelId string, term SEARCH_CLAUSE INACTIVE_CLAUSE ORDER BY Users.Username ASC - LIMIT 100` + LIMIT :Limit` } - *result = us.performSearch(searchQuery, term, options, map[string]interface{}{"TeamId": teamId, "ChannelId": channelId}) - + *result = us.performSearch(searchQuery, term, options, map[string]interface{}{ + "TeamId": teamId, + "ChannelId": channelId, + "Limit": options.Limit, + }) }) } -func (us SqlUserStore) SearchInChannel(channelId string, term string, options map[string]bool) store.StoreChannel { +func (us SqlUserStore) SearchInChannel(channelId string, term string, options *model.UserSearchOptions) store.StoreChannel { return store.Do(func(result *store.StoreResult) { searchQuery := ` - SELECT - Users.* - FROM - Users, ChannelMembers - WHERE - ChannelMembers.ChannelId = :ChannelId - AND ChannelMembers.UserId = Users.Id - SEARCH_CLAUSE - INACTIVE_CLAUSE - ORDER BY Users.Username ASC - LIMIT 100` - - *result = us.performSearch(searchQuery, term, options, map[string]interface{}{"ChannelId": channelId}) + SELECT + Users.* + FROM + Users, ChannelMembers + WHERE + ChannelMembers.ChannelId = :ChannelId + AND ChannelMembers.UserId = Users.Id + SEARCH_CLAUSE + INACTIVE_CLAUSE + ORDER BY Users.Username ASC + LIMIT :Limit + ` + + *result = us.performSearch(searchQuery, term, options, map[string]interface{}{ + "ChannelId": channelId, + "Limit": options.Limit, + }) }) } @@ -1160,7 +1174,7 @@ func generateSearchQuery(searchQuery string, terms []string, fields []string, pa return strings.Replace(searchQuery, "SEARCH_CLAUSE", fmt.Sprintf(" AND %s ", searchClause), 1) } -func (us SqlUserStore) performSearch(searchQuery string, term string, options map[string]bool, parameters map[string]interface{}) store.StoreResult { +func (us SqlUserStore) performSearch(searchQuery string, term string, options *model.UserSearchOptions, parameters map[string]interface{}) store.StoreResult { result := store.StoreResult{} // These chars must be removed from the like query. @@ -1173,16 +1187,22 @@ func (us SqlUserStore) performSearch(searchQuery string, term string, options ma term = strings.Replace(term, c, "*"+c, -1) } - searchType := USER_SEARCH_TYPE_ALL - if ok := options[store.USER_SEARCH_OPTION_NAMES_ONLY]; ok { - searchType = USER_SEARCH_TYPE_NAMES - } else if ok = options[store.USER_SEARCH_OPTION_NAMES_ONLY_NO_FULL_NAME]; ok { - searchType = USER_SEARCH_TYPE_NAMES_NO_FULL_NAME - } else if ok = options[store.USER_SEARCH_OPTION_ALL_NO_FULL_NAME]; ok { - searchType = USER_SEARCH_TYPE_ALL_NO_FULL_NAME + searchType := USER_SEARCH_TYPE_NAMES_NO_FULL_NAME + if options.AllowEmails { + if options.AllowFullNames { + searchType = USER_SEARCH_TYPE_ALL + } else { + searchType = USER_SEARCH_TYPE_ALL_NO_FULL_NAME + } + } else { + if options.AllowFullNames { + searchType = USER_SEARCH_TYPE_NAMES + } else { + searchType = USER_SEARCH_TYPE_NAMES_NO_FULL_NAME + } } - if ok := options[store.USER_SEARCH_OPTION_ALLOW_INACTIVE]; ok { + if ok := options.AllowInactive; ok { searchQuery = strings.Replace(searchQuery, "INACTIVE_CLAUSE", "", 1) } else { searchQuery = strings.Replace(searchQuery, "INACTIVE_CLAUSE", "AND Users.DeleteAt = 0", 1) -- cgit v1.2.3-1-g7c22