diff --git a/api4/user.go b/api4/user.go index c9b33375ef..1d9f848d81 100644 --- a/api4/user.go +++ b/api4/user.go @@ -885,9 +885,18 @@ func autocompleteUsers(c *Context, w http.ResponseWriter, r *http.Request) { } if len(channelId) > 0 { - // Applying the provided teamId here is useful for DMs and GMs which don't belong - // to a team. Applying it when the channel does belong to a team makes less sense, - // but the permissions are checked above regardless. + // We're using the channelId to search for users inside that channel and the team + // to get the not in channel list. Also we want to include the DM and GM users for + // that team which could only be obtained having the team id. + if len(teamId) == 0 { + c.Err = model.NewAppError("autocompleteUser", + "api.user.autocomplete_users.missing_team_id.app_error", + nil, + "channelId="+channelId, + http.StatusInternalServerError, + ) + return + } result, err := c.App.AutocompleteUsersInChannel(teamId, channelId, name, options) if err != nil { c.Err = err diff --git a/api4/user_test.go b/api4/user_test.go index 3864a8266c..794e34afeb 100644 --- a/api4/user_test.go +++ b/api4/user_test.go @@ -1148,6 +1148,7 @@ func TestAutocompleteUsersInChannel(t *testing.T) { Username string ExpectedResults int MoreThan bool + ShouldFail bool }{ { "Autocomplete in channel for specific username", @@ -1156,6 +1157,7 @@ func TestAutocompleteUsersInChannel(t *testing.T) { username, 1, false, + false, }, { "Search for not valid username", @@ -1164,6 +1166,7 @@ func TestAutocompleteUsersInChannel(t *testing.T) { "amazonses", 0, false, + false, }, { "Search for all users", @@ -1172,14 +1175,16 @@ func TestAutocompleteUsersInChannel(t *testing.T) { "", 2, true, + false, }, { - "Search all in specific channel", + "Fail when the teamId is not provided", "", channelId, "", 2, true, + true, }, } @@ -1187,12 +1192,17 @@ func TestAutocompleteUsersInChannel(t *testing.T) { t.Run(tc.Name, func(t *testing.T) { th.LoginBasic() rusers, resp := th.Client.AutocompleteUsersInChannel(tc.TeamId, tc.ChannelId, tc.Username, model.USER_SEARCH_DEFAULT_LIMIT, "") - CheckNoError(t, resp) - if tc.MoreThan { - assert.True(t, len(rusers.Users) >= tc.ExpectedResults) + if tc.ShouldFail { + CheckErrorMessage(t, resp, "api.user.autocomplete_users.missing_team_id.app_error") } else { - assert.Len(t, rusers.Users, tc.ExpectedResults) + CheckNoError(t, resp) + if tc.MoreThan { + assert.True(t, len(rusers.Users) >= tc.ExpectedResults) + } else { + assert.Len(t, rusers.Users, tc.ExpectedResults) + } } + th.Client.Logout() _, resp = th.Client.AutocompleteUsersInChannel(tc.TeamId, tc.ChannelId, tc.Username, model.USER_SEARCH_DEFAULT_LIMIT, "") CheckUnauthorizedStatus(t, resp) diff --git a/i18n/en.json b/i18n/en.json index d12f7a6d59..5f449ec5ab 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -2506,6 +2506,10 @@ "id": "api.user.authorize_oauth_user.unsupported.app_error", "translation": "Unsupported OAuth service provider." }, + { + "id": "api.user.autocomplete_users.missing_team_id.app_error", + "translation": "Team id parameter is required to autocomplete by channel." + }, { "id": "api.user.check_user_login_attempts.too_many.app_error", "translation": "Your account is locked because of too many failed password attempts. Please reset your password." @@ -6166,10 +6170,6 @@ "id": "store.insert_error", "translation": "insert error" }, - { - "id": "store.search_user_store.empty_team_id", - "translation": "Failed to get list of allowed channels for team: empty teamId" - }, { "id": "store.select_error", "translation": "select error" diff --git a/store/searchlayer/user_layer.go b/store/searchlayer/user_layer.go index f1afbc9199..dcecc55b59 100644 --- a/store/searchlayer/user_layer.go +++ b/store/searchlayer/user_layer.go @@ -4,7 +4,6 @@ package searchlayer import ( - "net/http" "strings" "github.com/mattermost/mattermost-server/v5/mlog" @@ -104,7 +103,7 @@ func (s *SearchUserStore) autocompleteUsersInChannelByEngine(engine searchengine uchanIds := []string{} nuchanIds := []string{} sanitizedTerm := sanitizeSearchTerm(term) - if options.ListOfAllowedChannels != nil && !strings.Contains(strings.Join(options.ListOfAllowedChannels, "."), channelId) { + if channelId != "" && options.ListOfAllowedChannels != nil && !strings.Contains(strings.Join(options.ListOfAllowedChannels, "."), channelId) { nuchanIds, err = engine.SearchUsersInTeam(teamId, options.ListOfAllowedChannels, sanitizedTerm, options) } else { uchanIds, nuchanIds, err = engine.SearchUsersInChannel(teamId, channelId, options.ListOfAllowedChannels, sanitizedTerm, options) @@ -146,45 +145,49 @@ func (s *SearchUserStore) autocompleteUsersInChannelByEngine(engine searchengine return autocomplete, nil } +// getListOfAllowedChannelsForTeam return the list of allowed channels to search user based on the +// next scenarios: +// - If there isn't view restrictions (team or channel) and no team id to filter them, then all +// channels are allowed (nil return) +// - If we receive a team Id and either we don't have view restrictions or the provided team id is included in the +// list of restricted teams, then we return all the team channels +// - If we don't receive team id or the provided team id is not in the list of allowed teams to search of and we +// don't have channel restrictions then we return an empty result because we cannot get channels +// - If we receive channels restrictions we get: +// - If we don't have team id, we get those restricted channels (guest accounts and quick search) +// - If we have a team id then we only return those restricted channels that belongs to that team func (s *SearchUserStore) getListOfAllowedChannelsForTeam(teamId string, viewRestrictions *model.ViewUsersRestrictions) ([]string, *model.AppError) { - if len(teamId) == 0 { - return nil, model.NewAppError("SearchUserStore", "store.search_user_store.empty_team_id", nil, "", http.StatusInternalServerError) - } - var listOfAllowedChannels []string if viewRestrictions == nil && teamId == "" { + // nil return without error means all channels are allowed return nil, nil } - if viewRestrictions == nil || strings.Contains(strings.Join(viewRestrictions.Teams, "."), teamId) { + if teamId != "" && (viewRestrictions == nil || strings.Contains(strings.Join(viewRestrictions.Teams, "."), teamId)) { channels, err := s.rootStore.Channel().GetTeamChannels(teamId) if err != nil { return nil, err } - channelIds := []string{} for _, channel := range *channels { - channelIds = append(channelIds, channel.Id) + listOfAllowedChannels = append(listOfAllowedChannels, channel.Id) } - - return channelIds, nil + return listOfAllowedChannels, nil } - if len(viewRestrictions.Channels) == 0 { - return []string{}, nil - } - - channels, err := s.rootStore.Channel().GetChannelsByIds(viewRestrictions.Channels, false) - - if err != nil { - return nil, err - } - for _, c := range channels { - if c.TeamId == teamId { - listOfAllowedChannels = append(listOfAllowedChannels, c.Id) + if len(viewRestrictions.Channels) > 0 { + channels, err := s.rootStore.Channel().GetChannelsByIds(viewRestrictions.Channels, false) + if err != nil { + return nil, err } + for _, c := range channels { + if teamId == "" || (teamId != "" && c.TeamId == teamId) { + listOfAllowedChannels = append(listOfAllowedChannels, c.Id) + } + } + return listOfAllowedChannels, nil } - return listOfAllowedChannels, nil + return []string{}, nil } func (s *SearchUserStore) AutocompleteUsersInChannel(teamId, channelId, term string, options *model.UserSearchOptions) (*model.UserAutocompleteInChannel, *model.AppError) { @@ -195,7 +198,7 @@ func (s *SearchUserStore) AutocompleteUsersInChannel(teamId, channelId, term str mlog.Error("Encountered error on AutocompleteUsersInChannel.", mlog.String("search_engine", engine.GetName()), mlog.Err(err)) continue } - if len(listOfAllowedChannels) == 0 { + if listOfAllowedChannels != nil && len(listOfAllowedChannels) == 0 { return &model.UserAutocompleteInChannel{}, nil } options.ListOfAllowedChannels = listOfAllowedChannels diff --git a/store/searchtest/helper.go b/store/searchtest/helper.go index c385f70dea..e041c17166 100644 --- a/store/searchtest/helper.go +++ b/store/searchtest/helper.go @@ -29,6 +29,12 @@ type SearchTestHelper struct { } func (th *SearchTestHelper) SetupBasicFixtures() error { + // Remove users from previous tests + err := th.cleanAllUsers() + if err != nil { + return err + } + // Create teams team, err := th.createTeam("searchtest-team", "Searchtest team", model.TEAM_OPEN) if err != nil { @@ -132,17 +138,7 @@ func (th *SearchTestHelper) CleanFixtures() error { return err } - err = th.deleteUser(th.User) - if err != nil { - return err - } - - err = th.deleteUser(th.User2) - if err != nil { - return err - } - - err = th.deleteUser(th.UserAnotherTeam) + err = th.cleanAllUsers() if err != nil { return err } @@ -196,6 +192,23 @@ func (th *SearchTestHelper) createUser(username, nickname, firstName, lastName s return user, nil } +func (th *SearchTestHelper) createGuest(username, nickname, firstName, lastName string) (*model.User, error) { + user, appError := th.Store.User().Save(&model.User{ + Username: username, + Password: username, + Nickname: nickname, + FirstName: firstName, + LastName: lastName, + Email: th.makeEmail(), + Roles: model.SYSTEM_GUEST_ROLE_ID, + }) + if appError != nil { + return nil, errors.New(appError.Error()) + } + + return user, nil +} + func (th *SearchTestHelper) deleteUser(user *model.User) error { appError := th.Store.User().PermanentDelete(user.Id) if appError != nil { @@ -205,6 +218,22 @@ func (th *SearchTestHelper) deleteUser(user *model.User) error { return nil } +func (th *SearchTestHelper) cleanAllUsers() error { + users, apperr := th.Store.User().GetAll() + if apperr != nil { + return apperr + } + + for _, u := range users { + err := th.deleteUser(u) + if err != nil { + return err + } + } + + return nil +} + func (th *SearchTestHelper) createBot(username, displayName, ownerID string) (*model.Bot, error) { botModel := &model.Bot{ Username: username, diff --git a/store/searchtest/user_layer.go b/store/searchtest/user_layer.go index 045c0366a2..3a02d6796c 100644 --- a/store/searchtest/user_layer.go +++ b/store/searchtest/user_layer.go @@ -164,15 +164,30 @@ func TestSearchUserStore(t *testing.T, s store.Store, testEngine *SearchTestEngi } func testGetAllUsersInChannelWithEmptyTerm(t *testing.T, th *SearchTestHelper) { - options := &model.UserSearchOptions{ - AllowFullNames: true, - Limit: model.USER_SEARCH_DEFAULT_LIMIT, - } - users, err := th.Store.User().AutocompleteUsersInChannel(th.Team.Id, th.ChannelBasic.Id, "", options) - require.Nil(t, err) - th.assertUsersMatchInAnyOrder(t, []*model.User{th.User}, users.InChannel) - th.assertUsersMatchInAnyOrder(t, []*model.User{th.User2}, users.OutOfChannel) + t.Run("Return all users in team", func(t *testing.T) { + options := createDefaultOptions(true, false, false) + users, err := th.Store.User().AutocompleteUsersInChannel(th.Team.Id, th.ChannelBasic.Id, "", options) + require.Nil(t, err) + th.assertUsersMatchInAnyOrder(t, []*model.User{th.User}, users.InChannel) + th.assertUsersMatchInAnyOrder(t, []*model.User{th.User2}, users.OutOfChannel) + }) + t.Run("Return all users in teams even though some of them don't have a team associated", func(t *testing.T) { + options := createDefaultOptions(true, false, false) + userAlternate, err := th.createUser("user-alternate", "user-alternate", "user", "alternate") + require.Nil(t, err) + defer th.deleteUser(userAlternate) + userGuest, err := th.createGuest("user-guest", "user-guest", "user", "guest") + require.Nil(t, err) + defer th.deleteUser(userGuest) + + // In case teamId and channelId are empty our current logic goes through Search + users, err := th.Store.User().Search("", "", options) + require.Nil(t, err) + th.assertUsersMatchInAnyOrder(t, []*model.User{th.User, th.User2, th.UserAnotherTeam, + userAlternate, userGuest}, users) + }) } + func testHonorChannelRestrictionsAutocompletingUsers(t *testing.T, th *SearchTestHelper) { userAlternate, err := th.createUser("user-alternate", "user-alternate", "user", "alternate") require.Nil(t, err) @@ -181,71 +196,96 @@ func testHonorChannelRestrictionsAutocompletingUsers(t *testing.T, th *SearchTes require.Nil(t, err) _, err = th.addUserToChannels(userAlternate, []string{th.ChannelBasic.Id}) require.Nil(t, err) - options := &model.UserSearchOptions{ - AllowFullNames: true, - Limit: model.USER_SEARCH_DEFAULT_LIMIT, - ViewRestrictions: &model.ViewUsersRestrictions{Channels: []string{th.ChannelBasic.Id}}, - } + guest, err := th.createGuest("guest", "guest", "guest", "one") + require.Nil(t, err) + err = th.addUserToTeams(guest, []string{th.Team.Id}) + require.Nil(t, err) + _, err = th.addUserToChannels(guest, []string{th.ChannelBasic.Id}) + require.Nil(t, err) + defer th.deleteUser(guest) t.Run("Autocomplete users with channel restrictions", func(t *testing.T) { + options := createDefaultOptions(true, false, false) + options.ViewRestrictions = &model.ViewUsersRestrictions{Channels: []string{th.ChannelBasic.Id}} users, apperr := th.Store.User().AutocompleteUsersInChannel(th.Team.Id, th.ChannelBasic.Id, "", options) require.Nil(t, apperr) - th.assertUsersMatchInAnyOrder(t, []*model.User{th.User, userAlternate}, users.InChannel) + th.assertUsersMatchInAnyOrder(t, []*model.User{th.User, userAlternate, guest}, users.InChannel) th.assertUsersMatchInAnyOrder(t, []*model.User{}, users.OutOfChannel) }) t.Run("Autocomplete users with term and channel restrictions", func(t *testing.T) { + options := createDefaultOptions(true, false, false) + options.ViewRestrictions = &model.ViewUsersRestrictions{Channels: []string{th.ChannelBasic.Id}} users, apperr := th.Store.User().AutocompleteUsersInChannel(th.Team.Id, th.ChannelBasic.Id, "alt", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{userAlternate}, users.InChannel) th.assertUsersMatchInAnyOrder(t, []*model.User{}, users.OutOfChannel) }) t.Run("Autocomplete users with all channels restricted", func(t *testing.T) { + options := createDefaultOptions(true, false, false) options.ViewRestrictions = &model.ViewUsersRestrictions{Channels: []string{}} users, apperr := th.Store.User().AutocompleteUsersInChannel(th.Team.Id, th.ChannelBasic.Id, "", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{}, users.InChannel) th.assertUsersMatchInAnyOrder(t, []*model.User{}, users.OutOfChannel) }) + t.Run("Autocomplete users with all channels restricted but with empty team", func(t *testing.T) { + options := createDefaultOptions(true, false, false) + options.ViewRestrictions = &model.ViewUsersRestrictions{Channels: []string{}} + users, apperr := th.Store.User().AutocompleteUsersInChannel("", th.ChannelBasic.Id, "", options) + require.Nil(t, apperr) + th.assertUsersMatchInAnyOrder(t, []*model.User{}, users.InChannel) + th.assertUsersMatchInAnyOrder(t, []*model.User{}, users.OutOfChannel) + }) + t.Run("Autocomplete users with empty team and channels restricted", func(t *testing.T) { + options := createDefaultOptions(true, false, false) + options.ViewRestrictions = &model.ViewUsersRestrictions{Channels: []string{th.ChannelBasic.Id}} + // In case teamId and channelId are empty our current logic goes through Search + users, err := th.Store.User().Search("", "", options) + require.Nil(t, err) + th.assertUsersMatchInAnyOrder(t, []*model.User{userAlternate, guest, th.User}, users) + }) } + func testHonorTeamRestrictionsAutocompletingUsers(t *testing.T, th *SearchTestHelper) { - userAlternate, err := th.createUser("user-alternate", "user-alternate", "user", "alternate") - defer th.deleteUser(userAlternate) - require.Nil(t, err) - err = th.addUserToTeams(userAlternate, []string{th.AnotherTeam.Id}) - require.Nil(t, err) - _, err = th.addUserToChannels(userAlternate, []string{th.ChannelAnotherTeam.Id}) - require.Nil(t, err) - options := &model.UserSearchOptions{ - AllowFullNames: true, - Limit: model.USER_SEARCH_DEFAULT_LIMIT, - ViewRestrictions: &model.ViewUsersRestrictions{Teams: []string{th.Team.Id}}, - } t.Run("Should return results for users in the team", func(t *testing.T) { + options := createDefaultOptions(true, false, false) + options.ViewRestrictions = &model.ViewUsersRestrictions{Teams: []string{th.Team.Id}} users, apperr := th.Store.User().AutocompleteUsersInChannel(th.Team.Id, th.ChannelBasic.Id, "", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{th.User}, users.InChannel) th.assertUsersMatchInAnyOrder(t, []*model.User{th.User2}, users.OutOfChannel) }) t.Run("Should return empty because we're filtering all the teams", func(t *testing.T) { + options := createDefaultOptions(true, false, false) options.ViewRestrictions = &model.ViewUsersRestrictions{Teams: []string{}} users, apperr := th.Store.User().AutocompleteUsersInChannel(th.Team.Id, th.ChannelBasic.Id, "", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{}, users.InChannel) th.assertUsersMatchInAnyOrder(t, []*model.User{}, users.OutOfChannel) }) + t.Run("Should return empty when searching in one team and filtering by another", func(t *testing.T) { + options := createDefaultOptions(true, false, false) + options.ViewRestrictions = &model.ViewUsersRestrictions{Teams: []string{th.AnotherTeam.Id}} + users, err := th.Store.User().Search(th.Team.Id, "", options) + require.Nil(t, err) + th.assertUsersMatchInAnyOrder(t, []*model.User{}, users) + + acusers, err := th.Store.User().AutocompleteUsersInChannel(th.Team.Id, th.ChannelBasic.Id, "", options) + require.Nil(t, err) + th.assertUsersMatchInAnyOrder(t, []*model.User{}, acusers.InChannel) + th.assertUsersMatchInAnyOrder(t, []*model.User{}, acusers.OutOfChannel) + }) } func testShouldReturnNothingWithoutProperAccess(t *testing.T, th *SearchTestHelper) { - options := &model.UserSearchOptions{ - AllowFullNames: true, - Limit: model.USER_SEARCH_DEFAULT_LIMIT, - ListOfAllowedChannels: []string{th.ChannelBasic.Id}, - } t.Run("Should return results users for the defined channel in the list", func(t *testing.T) { + options := createDefaultOptions(true, false, false) + options.ListOfAllowedChannels = []string{th.ChannelBasic.Id} users, apperr := th.Store.User().AutocompleteUsersInChannel(th.Team.Id, th.ChannelBasic.Id, "", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{th.User}, users.InChannel) th.assertUsersMatchInAnyOrder(t, []*model.User{}, users.OutOfChannel) }) t.Run("Should return empty because we're filtering all the channels", func(t *testing.T) { + options := createDefaultOptions(true, false, false) options.ListOfAllowedChannels = []string{} users, apperr := th.Store.User().AutocompleteUsersInChannel(th.Team.Id, th.ChannelBasic.Id, "", options) require.Nil(t, apperr) @@ -261,10 +301,7 @@ func testAutocompleteUserByUsername(t *testing.T, th *SearchTestHelper) { require.Nil(t, err) _, err = th.addUserToChannels(userAlternate, []string{th.ChannelBasic.Id}) require.Nil(t, err) - options := &model.UserSearchOptions{ - AllowFullNames: false, - Limit: model.USER_SEARCH_DEFAULT_LIMIT, - } + options := createDefaultOptions(false, false, false) users, apperr := th.Store.User().AutocompleteUsersInChannel(th.Team.Id, th.ChannelBasic.Id, "basicusername", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{th.User}, users.InChannel) @@ -278,17 +315,15 @@ func testAutocompleteUserByFirstName(t *testing.T, th *SearchTestHelper) { require.Nil(t, err) _, err = th.addUserToChannels(userAlternate, []string{th.ChannelBasic.Id}) require.Nil(t, err) - options := &model.UserSearchOptions{ - AllowFullNames: true, - Limit: model.USER_SEARCH_DEFAULT_LIMIT, - } t.Run("Should autocomplete users when the first name is unique", func(t *testing.T) { + options := createDefaultOptions(true, false, false) users, apperr := th.Store.User().AutocompleteUsersInChannel(th.Team.Id, th.ChannelBasic.Id, "altfirstname", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{userAlternate}, users.InChannel) th.assertUsersMatchInAnyOrder(t, []*model.User{}, users.OutOfChannel) }) t.Run("Should autocomplete users for in the channel and out of the channel with the same first name", func(t *testing.T) { + options := createDefaultOptions(true, false, false) users, apperr := th.Store.User().AutocompleteUsersInChannel(th.Team.Id, th.ChannelBasic.Id, "basicfirstname", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{th.User}, users.InChannel) @@ -303,17 +338,15 @@ func testAutocompleteUserByLastName(t *testing.T, th *SearchTestHelper) { require.Nil(t, err) _, err = th.addUserToChannels(userAlternate, []string{th.ChannelBasic.Id}) require.Nil(t, err) - options := &model.UserSearchOptions{ - AllowFullNames: true, - Limit: model.USER_SEARCH_DEFAULT_LIMIT, - } t.Run("Should return results when the last name is unique", func(t *testing.T) { + options := createDefaultOptions(true, false, false) users, apperr := th.Store.User().AutocompleteUsersInChannel(th.Team.Id, th.ChannelBasic.Id, "altlastname", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{userAlternate}, users.InChannel) th.assertUsersMatchInAnyOrder(t, []*model.User{}, users.OutOfChannel) }) t.Run("Should return results for in the channel and out of the channel with the same last name", func(t *testing.T) { + options := createDefaultOptions(true, false, false) users, apperr := th.Store.User().AutocompleteUsersInChannel(th.Team.Id, th.ChannelBasic.Id, "basiclastname", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{th.User}, users.InChannel) @@ -328,17 +361,15 @@ func testAutocompleteUserByNickName(t *testing.T, th *SearchTestHelper) { require.Nil(t, err) _, err = th.addUserToChannels(userAlternate, []string{th.ChannelBasic.Id}) require.Nil(t, err) - options := &model.UserSearchOptions{ - AllowFullNames: true, - Limit: model.USER_SEARCH_DEFAULT_LIMIT, - } t.Run("Should return results when the nickname is unique", func(t *testing.T) { + options := createDefaultOptions(true, false, false) users, apperr := th.Store.User().AutocompleteUsersInChannel(th.Team.Id, th.ChannelBasic.Id, "alternatenickname", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{userAlternate}, users.InChannel) th.assertUsersMatchInAnyOrder(t, []*model.User{}, users.OutOfChannel) }) t.Run("Should return users that share the same part of the nickname", func(t *testing.T) { + options := createDefaultOptions(true, false, false) users, apperr := th.Store.User().AutocompleteUsersInChannel(th.Team.Id, th.ChannelBasic.Id, "basicnickname", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{th.User}, users.InChannel) @@ -356,49 +387,48 @@ func testAutocompleteUserByEmail(t *testing.T, th *SearchTestHelper) { require.Nil(t, err) _, err = th.addUserToChannels(userAlternate, []string{th.ChannelBasic.Id}) require.Nil(t, err) - options := &model.UserSearchOptions{ - AllowEmails: true, - Limit: model.USER_SEARCH_DEFAULT_LIMIT, - } t.Run("Should autocomplete users when the email is unique", func(t *testing.T) { + options := createDefaultOptions(false, true, false) users, apperr := th.Store.User().AutocompleteUsersInChannel(th.Team.Id, th.ChannelBasic.Id, "useralt@test.email.com", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{userAlternate}, users.InChannel) th.assertUsersMatchInAnyOrder(t, []*model.User{}, users.OutOfChannel) }) t.Run("Should autocomplete users that share the same email user prefix", func(t *testing.T) { + options := createDefaultOptions(false, true, false) users, apperr := th.Store.User().AutocompleteUsersInChannel(th.Team.Id, th.ChannelBasic.Id, "success_", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{th.User}, users.InChannel) th.assertUsersMatchInAnyOrder(t, []*model.User{th.User2}, users.OutOfChannel) }) t.Run("Should autocomplete users that share the same email domain", func(t *testing.T) { + options := createDefaultOptions(false, true, false) users, apperr := th.Store.User().AutocompleteUsersInChannel(th.Team.Id, th.ChannelBasic.Id, "simulator.amazon.com", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{th.User}, users.InChannel) th.assertUsersMatchInAnyOrder(t, []*model.User{th.User2}, users.OutOfChannel) }) t.Run("Should search users when the email is unique", func(t *testing.T) { + options := createDefaultOptions(false, true, false) users, apperr := th.Store.User().Search(th.Team.Id, "useralt@test.email.com", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{userAlternate}, users) }) t.Run("Should search users that share the same email user prefix", func(t *testing.T) { + options := createDefaultOptions(false, true, false) users, apperr := th.Store.User().Search(th.Team.Id, "success_", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{th.User}, users) }) t.Run("Should search users that share the same email domain", func(t *testing.T) { + options := createDefaultOptions(false, true, false) users, apperr := th.Store.User().Search(th.Team.Id, "simulator.amazon.com", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{th.User}, users) }) } func testShouldNotMatchSpecificQueriesEmail(t *testing.T, th *SearchTestHelper) { - options := &model.UserSearchOptions{ - AllowEmails: false, - Limit: model.USER_SEARCH_DEFAULT_LIMIT, - } + options := createDefaultOptions(false, false, false) users, apperr := th.Store.User().AutocompleteUsersInChannel(th.Team.Id, th.ChannelBasic.Id, "success_", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{}, users.InChannel) @@ -412,22 +442,22 @@ func testAutocompleteUserByUsernameWithDot(t *testing.T, th *SearchTestHelper) { require.Nil(t, err) _, err = th.addUserToChannels(userAlternate, []string{th.ChannelBasic.Id}) require.Nil(t, err) - options := &model.UserSearchOptions{ - Limit: model.USER_SEARCH_DEFAULT_LIMIT, - } t.Run("Should return results when searching for the whole username with Dot", func(t *testing.T) { + options := createDefaultOptions(false, false, false) users, apperr := th.Store.User().AutocompleteUsersInChannel(th.Team.Id, th.ChannelBasic.Id, "alternate.username", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{userAlternate}, users.InChannel) th.assertUsersMatchInAnyOrder(t, []*model.User{}, users.OutOfChannel) }) t.Run("Should return results when searching for part of the username including the Dot", func(t *testing.T) { + options := createDefaultOptions(false, false, false) users, apperr := th.Store.User().AutocompleteUsersInChannel(th.Team.Id, th.ChannelBasic.Id, ".username", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{userAlternate}, users.InChannel) th.assertUsersMatchInAnyOrder(t, []*model.User{}, users.OutOfChannel) }) t.Run("Should return results when searching for part of the username not including the Dot", func(t *testing.T) { + options := createDefaultOptions(false, false, false) users, apperr := th.Store.User().AutocompleteUsersInChannel(th.Team.Id, th.ChannelBasic.Id, "username", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{userAlternate}, users.InChannel) @@ -442,22 +472,22 @@ func testAutocompleteUserByUsernameWithUnderscore(t *testing.T, th *SearchTestHe require.Nil(t, err) _, err = th.addUserToChannels(userAlternate, []string{th.ChannelBasic.Id}) require.Nil(t, err) - options := &model.UserSearchOptions{ - Limit: model.USER_SEARCH_DEFAULT_LIMIT, - } t.Run("Should return results when searching for the whole username with underscore", func(t *testing.T) { + options := createDefaultOptions(false, false, false) users, apperr := th.Store.User().AutocompleteUsersInChannel(th.Team.Id, th.ChannelBasic.Id, "alternate_username", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{userAlternate}, users.InChannel) th.assertUsersMatchInAnyOrder(t, []*model.User{}, users.OutOfChannel) }) t.Run("Should return results when searching for part of the username including the underscore", func(t *testing.T) { + options := createDefaultOptions(false, false, false) users, apperr := th.Store.User().AutocompleteUsersInChannel(th.Team.Id, th.ChannelBasic.Id, "_username", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{userAlternate}, users.InChannel) th.assertUsersMatchInAnyOrder(t, []*model.User{}, users.OutOfChannel) }) t.Run("Should return results when searching for part of the username not including the underscore", func(t *testing.T) { + options := createDefaultOptions(false, false, false) users, apperr := th.Store.User().AutocompleteUsersInChannel(th.Team.Id, th.ChannelBasic.Id, "username", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{userAlternate}, users.InChannel) @@ -472,22 +502,22 @@ func testAutocompleteUserByUsernameWithHyphen(t *testing.T, th *SearchTestHelper require.Nil(t, err) _, err = th.addUserToChannels(userAlternate, []string{th.ChannelBasic.Id}) require.Nil(t, err) - options := &model.UserSearchOptions{ - Limit: model.USER_SEARCH_DEFAULT_LIMIT, - } t.Run("Should return results when searching for the whole username with hyphen", func(t *testing.T) { + options := createDefaultOptions(false, false, false) users, apperr := th.Store.User().AutocompleteUsersInChannel(th.Team.Id, th.ChannelBasic.Id, "alternate-username", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{userAlternate}, users.InChannel) th.assertUsersMatchInAnyOrder(t, []*model.User{}, users.OutOfChannel) }) t.Run("Should return results when searching for part of the username including the hyphen", func(t *testing.T) { + options := createDefaultOptions(false, false, false) users, apperr := th.Store.User().AutocompleteUsersInChannel(th.Team.Id, th.ChannelBasic.Id, "-username", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{userAlternate}, users.InChannel) th.assertUsersMatchInAnyOrder(t, []*model.User{}, users.OutOfChannel) }) t.Run("Should return results when searching for part of the username not including the hyphen", func(t *testing.T) { + options := createDefaultOptions(false, false, false) users, apperr := th.Store.User().AutocompleteUsersInChannel(th.Team.Id, th.ChannelBasic.Id, "username", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{userAlternate}, users.InChannel) @@ -503,16 +533,15 @@ func testShouldEscapePercentageCharacter(t *testing.T, th *SearchTestHelper) { require.Nil(t, err) _, err = th.addUserToChannels(userAlternate, []string{th.ChannelBasic.Id}) require.Nil(t, err) - options := &model.UserSearchOptions{ - Limit: model.USER_SEARCH_DEFAULT_LIMIT, - } t.Run("Should autocomplete users escaping percentage symbol", func(t *testing.T) { + options := createDefaultOptions(false, false, false) users, apperr := th.Store.User().AutocompleteUsersInChannel(th.Team.Id, th.ChannelBasic.Id, "alternate%", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{userAlternate}, users.InChannel) th.assertUsersMatchInAnyOrder(t, []*model.User{}, users.OutOfChannel) }) t.Run("Should search users escaping percentage symbol", func(t *testing.T) { + options := createDefaultOptions(false, false, false) users, apperr := th.Store.User().Search(th.Team.Id, "alternate%", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{userAlternate}, users) @@ -526,16 +555,15 @@ func testShouldEscapeUnderscoreCharacter(t *testing.T, th *SearchTestHelper) { require.Nil(t, err) _, err = th.addUserToChannels(userAlternate, []string{th.ChannelBasic.Id}) require.Nil(t, err) - options := &model.UserSearchOptions{ - Limit: model.USER_SEARCH_DEFAULT_LIMIT, - } t.Run("Should autocomplete users escaping underscore symbol", func(t *testing.T) { + options := createDefaultOptions(false, false, false) users, apperr := th.Store.User().AutocompleteUsersInChannel(th.Team.Id, th.ChannelBasic.Id, "alternate_", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{userAlternate}, users.InChannel) th.assertUsersMatchInAnyOrder(t, []*model.User{}, users.OutOfChannel) }) t.Run("Should search users escaping underscore symbol", func(t *testing.T) { + options := createDefaultOptions(false, false, false) users, apperr := th.Store.User().Search(th.Team.Id, "alternate_", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{userAlternate}, users) @@ -553,31 +581,28 @@ func testShouldBeAbleToSearchInactiveUsers(t *testing.T, th *SearchTestHelper) { require.Nil(t, err) _, err = th.addUserToChannels(userAlternate, []string{th.ChannelBasic.Id}) require.Nil(t, err) - options := &model.UserSearchOptions{ - Limit: model.USER_SEARCH_DEFAULT_LIMIT, - } t.Run("Should autocomplete inactive users if we allow it", func(t *testing.T) { - options.AllowInactive = true + options := createDefaultOptions(false, false, true) users, apperr := th.Store.User().AutocompleteUsersInChannel(th.Team.Id, th.ChannelBasic.Id, "basicusername", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{th.User, userAlternate}, users.InChannel) th.assertUsersMatchInAnyOrder(t, []*model.User{th.User2}, users.OutOfChannel) }) t.Run("Should search inactive users if we allow it", func(t *testing.T) { - options.AllowInactive = true + options := createDefaultOptions(false, false, true) users, apperr := th.Store.User().Search(th.Team.Id, "basicusername", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{th.User, th.User2, userAlternate}, users) }) t.Run("Shouldn't autocomplete inactive users if we don't allow it", func(t *testing.T) { - options.AllowInactive = false + options := createDefaultOptions(false, false, false) users, apperr := th.Store.User().AutocompleteUsersInChannel(th.Team.Id, th.ChannelBasic.Id, "basicusername", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{th.User}, users.InChannel) th.assertUsersMatchInAnyOrder(t, []*model.User{th.User2}, users.OutOfChannel) }) t.Run("Shouldn't search inactive users if we don't allow it", func(t *testing.T) { - options.AllowInactive = false + options := createDefaultOptions(false, false, false) users, apperr := th.Store.User().Search(th.Team.Id, "basicusername", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{th.User, th.User2}, users) @@ -595,18 +620,17 @@ func testShouldBeAbleToSearchFilteringByRole(t *testing.T, th *SearchTestHelper) require.Nil(t, err) _, err = th.addUserToChannels(userAlternate, []string{th.ChannelBasic.Id}) require.Nil(t, err) - options := &model.UserSearchOptions{ - AllowInactive: true, - Role: "system_admin", - Limit: model.USER_SEARCH_DEFAULT_LIMIT, - } t.Run("Should autocomplete users filtering by roles", func(t *testing.T) { + options := createDefaultOptions(false, false, true) + options.Role = "system_admin" users, apperr := th.Store.User().AutocompleteUsersInChannel(th.Team.Id, th.ChannelBasic.Id, "basicusername", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{userAlternate}, users.InChannel) th.assertUsersMatchInAnyOrder(t, []*model.User{}, users.OutOfChannel) }) t.Run("Should search users filtering by roles", func(t *testing.T) { + options := createDefaultOptions(false, false, true) + options.Role = "system_admin" users, apperr := th.Store.User().Search(th.Team.Id, "basicusername", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{userAlternate}, users) @@ -614,16 +638,15 @@ func testShouldBeAbleToSearchFilteringByRole(t *testing.T, th *SearchTestHelper) } func testShouldIgnoreLeadingAtSymbols(t *testing.T, th *SearchTestHelper) { - options := &model.UserSearchOptions{ - Limit: model.USER_SEARCH_DEFAULT_LIMIT, - } t.Run("Should autocomplete ignoring the @ symbol at the beginning", func(t *testing.T) { + options := createDefaultOptions(false, false, false) users, apperr := th.Store.User().AutocompleteUsersInChannel(th.Team.Id, th.ChannelBasic.Id, "@basicusername", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{th.User}, users.InChannel) th.assertUsersMatchInAnyOrder(t, []*model.User{th.User2}, users.OutOfChannel) }) t.Run("Should search ignoring the @ symbol at the beginning", func(t *testing.T) { + options := createDefaultOptions(false, false, false) users, apperr := th.Store.User().Search(th.Team.Id, "@basicusername", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{th.User, th.User2}, users) @@ -631,9 +654,7 @@ func testShouldIgnoreLeadingAtSymbols(t *testing.T, th *SearchTestHelper) { } func testSearchUsersShouldBeCaseInsensitive(t *testing.T, th *SearchTestHelper) { - options := &model.UserSearchOptions{ - Limit: model.USER_SEARCH_DEFAULT_LIMIT, - } + options := createDefaultOptions(false, false, false) users, apperr := th.Store.User().AutocompleteUsersInChannel(th.Team.Id, th.ChannelBasic.Id, "BaSiCUsErNaMe", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{th.User}, users.InChannel) @@ -649,17 +670,15 @@ func testSearchOneTwoCharUsersnameAndFirstLastNames(t *testing.T, th *SearchTest require.Nil(t, err) _, err = th.addUserToChannels(userAlternate, []string{th.ChannelBasic.Id}) require.Nil(t, err) - options := &model.UserSearchOptions{ - AllowFullNames: true, - Limit: model.USER_SEARCH_DEFAULT_LIMIT, - } t.Run("Should support two characters in the full name", func(t *testing.T) { + options := createDefaultOptions(true, false, false) users, apperr := th.Store.User().AutocompleteUsersInChannel(th.Team.Id, th.ChannelBasic.Id, "zi", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{userAlternate}, users.InChannel) th.assertUsersMatchInAnyOrder(t, []*model.User{}, users.OutOfChannel) }) t.Run("Should support two characters in the username", func(t *testing.T) { + options := createDefaultOptions(true, false, false) users, apperr := th.Store.User().AutocompleteUsersInChannel(th.Team.Id, th.ChannelBasic.Id, "ho", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{userAlternate}, users.InChannel) @@ -676,17 +695,15 @@ func testShouldSupportKoreanCharacters(t *testing.T, th *SearchTestHelper) { require.Nil(t, err) _, err = th.addUserToChannels(userAlternate, []string{th.ChannelBasic.Id}) require.Nil(t, err) - options := &model.UserSearchOptions{ - AllowFullNames: true, - Limit: model.USER_SEARCH_DEFAULT_LIMIT, - } t.Run("Should support hanja korean characters", func(t *testing.T) { + options := createDefaultOptions(true, false, false) users, apperr := th.Store.User().AutocompleteUsersInChannel(th.Team.Id, th.ChannelBasic.Id, "서강준", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{userAlternate}, users.InChannel) th.assertUsersMatchInAnyOrder(t, []*model.User{}, users.OutOfChannel) }) t.Run("Should support hangul korean characters", func(t *testing.T) { + options := createDefaultOptions(true, false, false) users, apperr := th.Store.User().AutocompleteUsersInChannel(th.Team.Id, th.ChannelBasic.Id, "안신원", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{userAlternate}, users.InChannel) @@ -702,10 +719,7 @@ func testSearchWithHyphenAtTheEndOfTheTerm(t *testing.T, th *SearchTestHelper) { require.Nil(t, err) _, err = th.addUserToChannels(userAlternate, []string{th.ChannelBasic.Id}) require.Nil(t, err) - options := &model.UserSearchOptions{ - AllowFullNames: true, - Limit: model.USER_SEARCH_DEFAULT_LIMIT, - } + options := createDefaultOptions(true, false, false) users, apperr := th.Store.User().AutocompleteUsersInChannel(th.Team.Id, th.ChannelBasic.Id, "alternate-", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{userAlternate}, users.InChannel) @@ -713,36 +727,39 @@ func testSearchWithHyphenAtTheEndOfTheTerm(t *testing.T, th *SearchTestHelper) { } func testSearchUsersInTeam(t *testing.T, th *SearchTestHelper) { - options := &model.UserSearchOptions{ - Limit: model.USER_SEARCH_DEFAULT_LIMIT, - } t.Run("Should return all the team users", func(t *testing.T) { + options := createDefaultOptions(false, false, false) users, apperr := th.Store.User().Search(th.Team.Id, "", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{th.User, th.User2}, users) }) t.Run("Should return all the team users with no team id", func(t *testing.T) { + options := createDefaultOptions(false, false, false) users, apperr := th.Store.User().Search("", "basicusername", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{th.User, th.User2, th.UserAnotherTeam}, users) }) t.Run("Should return all the team users filtered by username", func(t *testing.T) { + options := createDefaultOptions(false, false, false) users, apperr := th.Store.User().Search(th.Team.Id, "basicusername1", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{th.User}, users) }) t.Run("Should not return spurious results", func(t *testing.T) { + options := createDefaultOptions(false, false, false) users, apperr := th.Store.User().Search(th.Team.Id, "falseuser", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{}, users) }) t.Run("Should return all the team users filtered by username and with channel restrictions", func(t *testing.T) { + options := createDefaultOptions(false, false, false) options.ViewRestrictions = &model.ViewUsersRestrictions{Channels: []string{th.ChannelBasic.Id}} users, apperr := th.Store.User().Search(th.Team.Id, "basicusername", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{th.User}, users) }) t.Run("Should return all the team users filtered by username and with all channel restricted", func(t *testing.T) { + options := createDefaultOptions(false, false, false) options.ViewRestrictions = &model.ViewUsersRestrictions{Channels: []string{}} users, apperr := th.Store.User().Search(th.Team.Id, "basicusername1", options) require.Nil(t, apperr) @@ -758,10 +775,7 @@ func testSearchUsersInTeamUsernameWithDot(t *testing.T, th *SearchTestHelper) { require.Nil(t, err) _, err = th.addUserToChannels(userAlternate, []string{th.ChannelBasic.Id}) require.Nil(t, err) - options := &model.UserSearchOptions{ - AllowFullNames: true, - Limit: model.USER_SEARCH_DEFAULT_LIMIT, - } + options := createDefaultOptions(true, false, false) users, apperr := th.Store.User().Search(th.Team.Id, "alternate.", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{userAlternate}, users) @@ -775,10 +789,7 @@ func testSearchUsersInTeamUsernameWithHyphen(t *testing.T, th *SearchTestHelper) require.Nil(t, err) _, err = th.addUserToChannels(userAlternate, []string{th.ChannelBasic.Id}) require.Nil(t, err) - options := &model.UserSearchOptions{ - AllowFullNames: true, - Limit: model.USER_SEARCH_DEFAULT_LIMIT, - } + options := createDefaultOptions(true, false, false) users, apperr := th.Store.User().Search(th.Team.Id, "alternate-", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{userAlternate}, users) @@ -792,34 +803,38 @@ func testSearchUsersInTeamUsernameWithUnderscore(t *testing.T, th *SearchTestHel require.Nil(t, err) _, err = th.addUserToChannels(userAlternate, []string{th.ChannelBasic.Id}) require.Nil(t, err) - options := &model.UserSearchOptions{ - AllowFullNames: true, - Limit: model.USER_SEARCH_DEFAULT_LIMIT, - } + options := createDefaultOptions(true, false, false) users, apperr := th.Store.User().Search(th.Team.Id, "alternate_", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{userAlternate}, users) } func testSearchUsersByFullName(t *testing.T, th *SearchTestHelper) { - options := &model.UserSearchOptions{ - AllowFullNames: true, - Limit: model.USER_SEARCH_DEFAULT_LIMIT, - } t.Run("Should search users by full name", func(t *testing.T) { + options := createDefaultOptions(true, false, false) users, apperr := th.Store.User().Search(th.Team.Id, "basicfirstname", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{th.User, th.User2}, users) }) t.Run("Should search user by full name", func(t *testing.T) { + options := createDefaultOptions(true, false, false) users, apperr := th.Store.User().Search(th.Team.Id, "basicfirstname1", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{th.User}, users) }) t.Run("Should return empty when search by full name and is deactivated", func(t *testing.T) { - options.AllowFullNames = false + options := createDefaultOptions(false, false, false) users, apperr := th.Store.User().Search(th.Team.Id, "basicfirstname1", options) require.Nil(t, apperr) th.assertUsersMatchInAnyOrder(t, []*model.User{}, users) }) } + +func createDefaultOptions(allowFullName, allowEmails, allowInactive bool) *model.UserSearchOptions { + return &model.UserSearchOptions{ + AllowFullNames: allowFullName, + AllowEmails: allowEmails, + AllowInactive: allowInactive, + Limit: model.USER_SEARCH_DEFAULT_LIMIT, + } +}