MM-25263 Add group members to search and get users and create getGroupStats endpoint (#14733)

Add tests for SearchInGroup
Этот коммит содержится в:
Farhan Munshi
2020-06-18 10:22:35 -04:00
коммит произвёл GitHub
родитель f6c934d7e0
Коммит 77bee1d4f1
18 изменённых файлов: 517 добавлений и 2 удалений

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

@@ -52,6 +52,10 @@ func (api *API) InitGroup() {
api.BaseRoutes.Groups.Handle("/{group_id:[A-Za-z0-9]+}/{syncable_type:teams|channels}/{syncable_id:[A-Za-z0-9]+}/patch",
api.ApiSessionRequired(patchGroupSyncable)).Methods("PUT")
// GET /api/v4/groups/:group_id/stats
api.BaseRoutes.Groups.Handle("/{group_id:[A-Za-z0-9]+}/stats",
api.ApiSessionRequired(getGroupStats)).Methods("GET")
// GET /api/v4/groups/:group_id/members?page=0&per_page=100
api.BaseRoutes.Groups.Handle("/{group_id:[A-Za-z0-9]+}/members",
api.ApiSessionRequired(getGroupMembers)).Methods("GET")
@@ -530,6 +534,41 @@ func getGroupMembers(c *Context, w http.ResponseWriter, r *http.Request) {
w.Write(b)
}
func getGroupStats(c *Context, w http.ResponseWriter, r *http.Request) {
c.RequireGroupId()
if c.Err != nil {
return
}
if c.App.Srv().License() == nil || !*c.App.Srv().License().Features.LDAPGroups {
c.Err = model.NewAppError("Api4.getGroupStats", "api.ldap_groups.license_error", nil, "", http.StatusNotImplemented)
return
}
if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) {
c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM)
return
}
groupID := c.Params.GroupId
count, err := c.App.GetGroupMemberCount(groupID)
if err != nil {
c.Err = err
return
}
b, marshalErr := json.Marshal(model.GroupStats{
GroupID: groupID,
TotalMemberCount: count,
})
if marshalErr != nil {
c.Err = model.NewAppError("Api4.getGroupStats", "api.marshal_error", nil, marshalErr.Error(), http.StatusInternalServerError)
return
}
w.Write(b)
}
func getGroupsByUserId(c *Context, w http.ResponseWriter, r *http.Request) {
c.RequireUserId()
if c.Err != nil {

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

@@ -1024,6 +1024,54 @@ func TestGetGroupsByUserId(t *testing.T) {
}
func TestGetGroupStats(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
id := model.NewId()
group, err := th.App.CreateGroup(&model.Group{
DisplayName: "dn-foo_" + id,
Name: model.NewString("name" + id),
Source: model.GroupSourceLdap,
Description: "description_" + id,
RemoteId: model.NewId(),
})
assert.Nil(t, err)
var response *model.Response
var stats *model.GroupStats
t.Run("Requires ldap license", func(t *testing.T) {
_, response = th.SystemAdminClient.GetGroupStats(group.Id)
CheckNotImplementedStatus(t, response)
})
th.App.Srv().SetLicense(model.NewTestLicense("ldap"))
t.Run("Requires manage system permission to access group stats", func(t *testing.T) {
th.Client.Login(th.BasicUser.Email, th.BasicUser.Password)
_, response = th.Client.GetGroupStats(group.Id)
CheckForbiddenStatus(t, response)
})
t.Run("Returns stats for a group with no members", func(t *testing.T) {
stats, _ = th.SystemAdminClient.GetGroupStats(group.Id)
assert.Equal(t, stats.GroupID, group.Id)
assert.Equal(t, stats.TotalMemberCount, int64(0))
})
user1, err := th.App.CreateUser(&model.User{Email: th.GenerateTestEmail(), Nickname: "test user1", Password: "test-password-1", Username: "test-user-1", Roles: model.SYSTEM_USER_ROLE_ID})
assert.Nil(t, err)
_, err = th.App.UpsertGroupMember(group.Id, user1.Id)
assert.Nil(t, err)
t.Run("Returns stats for a group with members", func(t *testing.T) {
stats, _ = th.SystemAdminClient.GetGroupStats(group.Id)
assert.Equal(t, stats.GroupID, group.Id)
assert.Equal(t, stats.TotalMemberCount, int64(1))
})
}
func TestGetGroupsGroupConstrainedParentTeam(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()

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

@@ -527,6 +527,7 @@ func getUsers(c *Context, w http.ResponseWriter, r *http.Request) {
inTeamId := r.URL.Query().Get("in_team")
notInTeamId := r.URL.Query().Get("not_in_team")
inChannelId := r.URL.Query().Get("in_channel")
inGroupId := r.URL.Query().Get("in_group")
notInChannelId := r.URL.Query().Get("not_in_channel")
groupConstrained := r.URL.Query().Get("group_constrained")
withoutTeam := r.URL.Query().Get("without_team")
@@ -546,7 +547,7 @@ func getUsers(c *Context, w http.ResponseWriter, r *http.Request) {
// Currently only supports sorting on a team
// or sort="status" on inChannelId
if (sort == "last_activity_at" || sort == "create_at") && (inTeamId == "" || notInTeamId != "" || inChannelId != "" || notInChannelId != "" || withoutTeam != "") {
if (sort == "last_activity_at" || sort == "create_at") && (inTeamId == "" || notInTeamId != "" || inChannelId != "" || notInChannelId != "" || withoutTeam != "" || inGroupId != "") {
c.SetInvalidUrlParam("sort")
return
}
@@ -570,6 +571,7 @@ func getUsers(c *Context, w http.ResponseWriter, r *http.Request) {
InChannelId: inChannelId,
NotInTeamId: notInTeamId,
NotInChannelId: notInChannelId,
InGroupId: inGroupId,
GroupConstrained: groupConstrainedBool,
WithoutTeam: withoutTeamBool,
Inactive: inactiveBool,
@@ -637,6 +639,22 @@ func getUsers(c *Context, w http.ResponseWriter, r *http.Request) {
} else {
profiles, err = c.App.GetUsersInChannelPage(inChannelId, c.Params.Page, c.Params.PerPage, c.IsSystemAdmin())
}
} else if len(inGroupId) > 0 {
if c.App.Srv().License() == nil || !*c.App.Srv().License().Features.LDAPGroups {
c.Err = model.NewAppError("Api4.getUsersInGroup", "api.ldap_groups.license_error", nil, "", http.StatusNotImplemented)
return
}
if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) {
c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM)
return
}
profiles, _, err = c.App.GetGroupMemberUsersPage(inGroupId, c.Params.Page, c.Params.PerPage)
if err != nil {
c.Err = err
return
}
} else {
userGetOptions, err = c.App.RestrictUsersGetByPermissions(c.App.Session().UserId, userGetOptions)
if err != nil {
@@ -749,6 +767,18 @@ func searchUsers(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
if props.InGroupId != "" {
if c.App.Srv().License() == nil || !*c.App.Srv().License().Features.LDAPGroups {
c.Err = model.NewAppError("Api4.searchUsers", "api.ldap_groups.license_error", nil, "", http.StatusNotImplemented)
return
}
if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) {
c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM)
return
}
}
if props.InChannelId != "" && !c.App.SessionHasPermissionToChannel(*c.App.Session(), props.InChannelId, model.PERMISSION_READ_CHANNEL) {
c.SetPermissionError(model.PERMISSION_READ_CHANNEL)
return

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

@@ -1084,6 +1084,44 @@ func TestSearchUsers(t *testing.T) {
CheckNoError(t, resp)
require.True(t, findUserInList(th.BasicUser.Id, users), "should have found user")
id := model.NewId()
group, err := th.App.CreateGroup(&model.Group{
DisplayName: "dn-foo_" + id,
Name: model.NewString("name" + id),
Source: model.GroupSourceLdap,
Description: "description_" + id,
RemoteId: model.NewId(),
})
assert.Nil(t, err)
search = &model.UserSearch{Term: th.BasicUser.Username, InGroupId: group.Id}
t.Run("Requires ldap license when searching in group", func(t *testing.T) {
_, resp = th.SystemAdminClient.SearchUsers(search)
CheckNotImplementedStatus(t, resp)
})
th.App.Srv().SetLicense(model.NewTestLicense("ldap"))
t.Run("Requires manage system permission when searching for users in a group", func(t *testing.T) {
_, resp = th.Client.SearchUsers(search)
CheckForbiddenStatus(t, resp)
})
t.Run("Returns empty list when no users found searching for users in a group", func(t *testing.T) {
users, resp = th.SystemAdminClient.SearchUsers(search)
CheckNoError(t, resp)
require.Empty(t, users)
})
_, err = th.App.UpsertGroupMember(group.Id, th.BasicUser.Id)
assert.Nil(t, err)
t.Run("Returns user in group user found in group", func(t *testing.T) {
users, resp = th.SystemAdminClient.SearchUsers(search)
CheckNoError(t, resp)
require.Equal(t, users[0].Id, th.BasicUser.Id)
})
}
func findUserInList(id string, users []*model.User) bool {
@@ -2328,6 +2366,54 @@ func TestGetUsersNotInChannel(t *testing.T) {
CheckNoError(t, resp)
}
func TestGetUsersInGroup(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
id := model.NewId()
group, err := th.App.CreateGroup(&model.Group{
DisplayName: "dn-foo_" + id,
Name: model.NewString("name" + id),
Source: model.GroupSourceLdap,
Description: "description_" + id,
RemoteId: model.NewId(),
})
assert.Nil(t, err)
var response *model.Response
var users []*model.User
t.Run("Requires ldap license", func(t *testing.T) {
_, response = th.SystemAdminClient.GetUsersInGroup(group.Id, 0, 60, "")
CheckNotImplementedStatus(t, response)
})
th.App.Srv().SetLicense(model.NewTestLicense("ldap"))
t.Run("Requires manage system permission to access users in group", func(t *testing.T) {
th.Client.Login(th.BasicUser.Email, th.BasicUser.Password)
_, response = th.Client.GetUsersInGroup(group.Id, 0, 60, "")
CheckForbiddenStatus(t, response)
})
user1, err := th.App.CreateUser(&model.User{Email: th.GenerateTestEmail(), Nickname: "test user1", Password: "test-password-1", Username: "test-user-1", Roles: model.SYSTEM_USER_ROLE_ID})
assert.Nil(t, err)
_, err = th.App.UpsertGroupMember(group.Id, user1.Id)
assert.Nil(t, err)
t.Run("Returns users in group when called by system admin", func(t *testing.T) {
users, response = th.SystemAdminClient.GetUsersInGroup(group.Id, 0, 60, "")
CheckNoError(t, response)
assert.Equal(t, users[0].Id, user1.Id)
})
t.Run("Returns no users when pagination out of range", func(t *testing.T) {
users, response = th.SystemAdminClient.GetUsersInGroup(group.Id, 5, 60, "")
CheckNoError(t, response)
assert.Empty(t, users)
})
}
func TestUpdateUserMfa(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()

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

@@ -541,6 +541,7 @@ type AppIface interface {
GetGroupByName(name string, opts model.GroupSearchOpts) (*model.Group, *model.AppError)
GetGroupByRemoteID(remoteID string, groupSource model.GroupSource) (*model.Group, *model.AppError)
GetGroupChannel(userIds []string) (*model.Channel, *model.AppError)
GetGroupMemberCount(groupID string) (int64, *model.AppError)
GetGroupMemberUsers(groupID string) ([]*model.User, *model.AppError)
GetGroupMemberUsersPage(groupID string, page int, perPage int) ([]*model.User, int, *model.AppError)
GetGroupSyncable(groupID string, syncableID string, syncableType model.GroupSyncableType) (*model.GroupSyncable, *model.AppError)
@@ -836,6 +837,7 @@ type AppIface interface {
SearchUserAccessTokens(term string) ([]*model.UserAccessToken, *model.AppError)
SearchUsers(props *model.UserSearch, options *model.UserSearchOptions) ([]*model.User, *model.AppError)
SearchUsersInChannel(channelId string, term string, options *model.UserSearchOptions) ([]*model.User, *model.AppError)
SearchUsersInGroup(groupID string, term string, options *model.UserSearchOptions) ([]*model.User, *model.AppError)
SearchUsersInTeam(teamId, term string, options *model.UserSearchOptions) ([]*model.User, *model.AppError)
SearchUsersNotInChannel(teamId string, channelId string, term string, options *model.UserSearchOptions) ([]*model.User, *model.AppError)
SearchUsersNotInTeam(notInTeamId string, term string, options *model.UserSearchOptions) ([]*model.User, *model.AppError)

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

@@ -59,6 +59,10 @@ func (a *App) DeleteGroup(groupID string) (*model.Group, *model.AppError) {
return deletedGroup, err
}
func (a *App) GetGroupMemberCount(groupID string) (int64, *model.AppError) {
return a.Srv().Store.Group().GetMemberCount(groupID)
}
func (a *App) GetGroupMemberUsers(groupID string) ([]*model.User, *model.AppError) {
return a.Srv().Store.Group().GetMemberUsers(groupID)
}
@@ -69,7 +73,7 @@ func (a *App) GetGroupMemberUsersPage(groupID string, page int, perPage int) ([]
return nil, 0, err
}
count, err := a.Srv().Store.Group().GetMemberCount(groupID)
count, err := a.GetGroupMemberCount(groupID)
if err != nil {
return nil, 0, err
}

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

@@ -5311,6 +5311,28 @@ func (a *OpenTracingAppLayer) GetGroupChannel(userIds []string) (*model.Channel,
return resultVar0, resultVar1
}
func (a *OpenTracingAppLayer) GetGroupMemberCount(groupID string) (int64, *model.AppError) {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetGroupMemberCount")
a.ctx = newCtx
a.app.Srv().Store.SetContext(newCtx)
defer func() {
a.app.Srv().Store.SetContext(origCtx)
a.ctx = origCtx
}()
defer span.Finish()
resultVar0, resultVar1 := a.app.GetGroupMemberCount(groupID)
if resultVar1 != nil {
span.LogFields(spanlog.Error(resultVar1))
ext.Error.Set(span, true)
}
return resultVar0, resultVar1
}
func (a *OpenTracingAppLayer) GetGroupMemberUsers(groupID string) ([]*model.User, *model.AppError) {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetGroupMemberUsers")
@@ -12120,6 +12142,28 @@ func (a *OpenTracingAppLayer) SearchUsersInChannel(channelId string, term string
return resultVar0, resultVar1
}
func (a *OpenTracingAppLayer) SearchUsersInGroup(groupID string, term string, options *model.UserSearchOptions) ([]*model.User, *model.AppError) {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.SearchUsersInGroup")
a.ctx = newCtx
a.app.Srv().Store.SetContext(newCtx)
defer func() {
a.app.Srv().Store.SetContext(origCtx)
a.ctx = origCtx
}()
defer span.Finish()
resultVar0, resultVar1 := a.app.SearchUsersInGroup(groupID, term, options)
if resultVar1 != nil {
span.LogFields(spanlog.Error(resultVar1))
ext.Error.Set(span, true)
}
return resultVar0, resultVar1
}
func (a *OpenTracingAppLayer) SearchUsersInTeam(teamId string, term string, options *model.UserSearchOptions) ([]*model.User, *model.AppError) {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.SearchUsersInTeam")

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

@@ -1693,6 +1693,9 @@ func (a *App) SearchUsers(props *model.UserSearch, options *model.UserSearchOpti
if props.NotInTeamId != "" {
return a.SearchUsersNotInTeam(props.NotInTeamId, props.Term, options)
}
if props.InGroupId != "" {
return a.SearchUsersInGroup(props.InGroupId, props.Term, options)
}
return a.SearchUsersInTeam(props.TeamId, props.Term, options)
}
@@ -1768,6 +1771,20 @@ func (a *App) SearchUsersWithoutTeam(term string, options *model.UserSearchOptio
return users, nil
}
func (a *App) SearchUsersInGroup(groupID string, term string, options *model.UserSearchOptions) ([]*model.User, *model.AppError) {
term = strings.TrimSpace(term)
users, err := a.Srv().Store.User().SearchInGroup(groupID, term, options)
if err != nil {
return nil, err
}
for _, user := range users {
a.SanitizeProfile(user, options.IsAdmin)
}
return users, nil
}
func (a *App) AutocompleteUsersInChannel(teamId string, channelId string, term string, options *model.UserSearchOptions) (*model.UserAutocompleteInChannel, *model.AppError) {
term = strings.TrimSpace(term)

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

@@ -994,6 +994,17 @@ func (c *Client4) GetUsersWithoutTeam(page int, perPage int, etag string) ([]*Us
return UserListFromJson(r.Body), BuildResponse(r)
}
// GetUsersInGroup returns a page of users in a group. Page counting starts at 0.
func (c *Client4) GetUsersInGroup(groupID string, page int, perPage int, etag string) ([]*User, *Response) {
query := fmt.Sprintf("?in_group=%v&page=%v&per_page=%v", groupID, page, perPage)
r, err := c.DoApiGet(c.GetUsersRoute()+query, etag)
if err != nil {
return nil, BuildErrorResponse(r, err)
}
defer closeBody(r)
return UserListFromJson(r.Body), BuildResponse(r)
}
// GetUsersByIds returns a list of users based on the provided user ids.
func (c *Client4) GetUsersByIds(userIds []string) ([]*User, *Response) {
r, err := c.DoApiPost(c.GetUsersRoute()+"/ids", ArrayToJson(userIds))
@@ -5127,3 +5138,13 @@ func (c *Client4) RequestTrialLicense(users int) (bool, *Response) {
defer closeBody(r)
return CheckStatusOK(r), BuildResponse(r)
}
// GetGroupStats retrieves stats for a Mattermost Group
func (c *Client4) GetGroupStats(groupID string) (*GroupStats, *Response) {
r, appErr := c.DoApiGet(c.GetGroupRoute(groupID)+"/stats", "")
if appErr != nil {
return nil, BuildErrorResponse(r, appErr)
}
defer closeBody(r)
return GroupStatsFromJson(r.Body), BuildResponse(r)
}

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

@@ -94,6 +94,11 @@ type PageOpts struct {
PerPage int
}
type GroupStats struct {
GroupID string `json:"group_id"`
TotalMemberCount int64 `json:"total_member_count"`
}
func (group *Group) Patch(patch *GroupPatch) {
if patch.Name != nil {
group.Name = patch.Name
@@ -208,3 +213,9 @@ func GroupPatchFromJson(data io.Reader) *GroupPatch {
json.NewDecoder(data).Decode(&groupPatch)
return groupPatch
}
func GroupStatsFromJson(data io.Reader) *GroupStats {
var groupStats *GroupStats
json.NewDecoder(data).Decode(&groupStats)
return groupStats
}

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

@@ -12,6 +12,8 @@ type UserGetOptions struct {
InChannelId string
// Filters the users not in the channel
NotInChannelId string
// Filters the users in the group
InGroupId string
// Filters the users group constrained
GroupConstrained bool
// Filters the users without a team

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

@@ -18,6 +18,7 @@ type UserSearch struct {
NotInTeamId string `json:"not_in_team_id"`
InChannelId string `json:"in_channel_id"`
NotInChannelId string `json:"not_in_channel_id"`
InGroupId string `json:"in_group_id"`
GroupConstrained bool `json:"group_constrained"`
AllowInactive bool `json:"allow_inactive"`
WithoutTeam bool `json:"without_team"`

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

@@ -8225,6 +8225,24 @@ func (s *OpenTracingLayerUserStore) SearchInChannel(channelId string, term strin
return resultVar0, resultVar1
}
func (s *OpenTracingLayerUserStore) SearchInGroup(groupID string, term string, options *model.UserSearchOptions) ([]*model.User, *model.AppError) {
origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "UserStore.SearchInGroup")
s.Root.Store.SetContext(newCtx)
defer func() {
s.Root.Store.SetContext(origCtx)
}()
defer span.Finish()
resultVar0, resultVar1 := s.UserStore.SearchInGroup(groupID, term, options)
if resultVar1 != nil {
span.LogFields(spanlog.Error(resultVar1))
ext.Error.Set(span, true)
}
return resultVar0, resultVar1
}
func (s *OpenTracingLayerUserStore) SearchNotInChannel(teamId string, channelId string, term string, options *model.UserSearchOptions) ([]*model.User, *model.AppError) {
origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "UserStore.SearchNotInChannel")

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

@@ -1240,6 +1240,15 @@ func (us SqlUserStore) SearchInChannel(channelId string, term string, options *m
return us.performSearch(query, term, options)
}
func (us SqlUserStore) SearchInGroup(groupID string, term string, options *model.UserSearchOptions) ([]*model.User, *model.AppError) {
query := us.usersQuery.
Join("GroupMembers gm ON ( gm.UserId = u.Id AND gm.GroupId = ? )", groupID).
OrderBy("Username ASC").
Limit(uint64(options.Limit))
return us.performSearch(query, term, options)
}
var spaceFulltextSearchChar = []string{
"<",
">",

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

@@ -322,6 +322,7 @@ type UserStore interface {
SearchInChannel(channelId string, term string, options *model.UserSearchOptions) ([]*model.User, *model.AppError)
SearchNotInChannel(teamId string, channelId string, term string, options *model.UserSearchOptions) ([]*model.User, *model.AppError)
SearchWithoutTeam(term string, options *model.UserSearchOptions) ([]*model.User, *model.AppError)
SearchInGroup(groupID string, term string, options *model.UserSearchOptions) ([]*model.User, *model.AppError)
AnalyticsGetInactiveUsersCount() (int64, *model.AppError)
AnalyticsGetSystemAdminCount() (int64, *model.AppError)
AnalyticsGetGuestCount() (int64, *model.AppError)

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

@@ -1164,6 +1164,31 @@ func (_m *UserStore) SearchInChannel(channelId string, term string, options *mod
return r0, r1
}
// SearchInGroup provides a mock function with given fields: groupID, term, options
func (_m *UserStore) SearchInGroup(groupID string, term string, options *model.UserSearchOptions) ([]*model.User, *model.AppError) {
ret := _m.Called(groupID, term, options)
var r0 []*model.User
if rf, ok := ret.Get(0).(func(string, string, *model.UserSearchOptions) []*model.User); ok {
r0 = rf(groupID, term, options)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]*model.User)
}
}
var r1 *model.AppError
if rf, ok := ret.Get(1).(func(string, string, *model.UserSearchOptions) *model.AppError); ok {
r1 = rf(groupID, term, options)
} else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)
}
}
return r0, r1
}
// SearchNotInChannel provides a mock function with given fields: teamId, channelId, term, options
func (_m *UserStore) SearchNotInChannel(teamId string, channelId string, term string, options *model.UserSearchOptions) ([]*model.User, *model.AppError) {
ret := _m.Called(teamId, channelId, term, options)

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

@@ -72,6 +72,7 @@ func TestUserStore(t *testing.T, ss store.Store, s SqlSupplier) {
t.Run("SearchInChannel", func(t *testing.T) { testUserStoreSearchInChannel(t, ss) })
t.Run("SearchNotInTeam", func(t *testing.T) { testUserStoreSearchNotInTeam(t, ss) })
t.Run("SearchWithoutTeam", func(t *testing.T) { testUserStoreSearchWithoutTeam(t, ss) })
t.Run("SearchInGroup", func(t *testing.T) { testUserStoreSearchInGroup(t, ss) })
t.Run("GetProfilesNotInTeam", func(t *testing.T) { testUserStoreGetProfilesNotInTeam(t, ss) })
t.Run("ClearAllCustomRoleAssignments", func(t *testing.T) { testUserStoreClearAllCustomRoleAssignments(t, ss) })
t.Run("GetAllAfter", func(t *testing.T) { testUserStoreGetAllAfter(t, ss) })
@@ -2918,6 +2919,146 @@ func testUserStoreSearchWithoutTeam(t *testing.T, ss store.Store) {
}
}
func testUserStoreSearchInGroup(t *testing.T, ss store.Store) {
u1 := &model.User{
Username: "jimbo1" + model.NewId(),
FirstName: "Tim",
LastName: "Bill",
Nickname: "Rob",
Email: "harold" + model.NewId() + "@simulator.amazonses.com",
}
_, err := ss.User().Save(u1)
require.Nil(t, err)
defer func() { require.Nil(t, ss.User().PermanentDelete(u1.Id)) }()
u2 := &model.User{
Username: "jim-bobby" + model.NewId(),
Email: MakeEmail(),
}
_, err = ss.User().Save(u2)
require.Nil(t, err)
defer func() { require.Nil(t, ss.User().PermanentDelete(u2.Id)) }()
u3 := &model.User{
Username: "jimbo3" + model.NewId(),
Email: MakeEmail(),
DeleteAt: 1,
}
_, err = ss.User().Save(u3)
require.Nil(t, err)
defer func() { require.Nil(t, ss.User().PermanentDelete(u3.Id)) }()
// The users returned from the database will have AuthData as an empty string.
nilAuthData := model.NewString("")
u1.AuthData = nilAuthData
u2.AuthData = nilAuthData
u3.AuthData = nilAuthData
g1 := &model.Group{
Name: model.NewString(model.NewId()),
DisplayName: model.NewId(),
Description: model.NewId(),
Source: model.GroupSourceLdap,
RemoteId: model.NewId(),
}
_, err = ss.Group().Create(g1)
require.Nil(t, err)
g2 := &model.Group{
Name: model.NewString(model.NewId()),
DisplayName: model.NewId(),
Description: model.NewId(),
Source: model.GroupSourceLdap,
RemoteId: model.NewId(),
}
_, err = ss.Group().Create(g2)
require.Nil(t, err)
_, err = ss.Group().UpsertMember(g1.Id, u1.Id)
require.Nil(t, err)
_, err = ss.Group().UpsertMember(g2.Id, u2.Id)
require.Nil(t, err)
_, err = ss.Group().UpsertMember(g1.Id, u3.Id)
require.Nil(t, err)
testCases := []struct {
Description string
GroupId string
Term string
Options *model.UserSearchOptions
Expected []*model.User
}{
{
"search jimb, group 1",
g1.Id,
"jimb",
&model.UserSearchOptions{
AllowFullNames: true,
Limit: model.USER_SEARCH_DEFAULT_LIMIT,
},
[]*model.User{u1},
},
{
"search jimb, group 1, allow inactive",
g1.Id,
"jimb",
&model.UserSearchOptions{
AllowFullNames: true,
AllowInactive: true,
Limit: model.USER_SEARCH_DEFAULT_LIMIT,
},
[]*model.User{u1, u3},
},
{
"search jimb, group 1, limit 1",
g1.Id,
"jimb",
&model.UserSearchOptions{
AllowFullNames: true,
AllowInactive: true,
Limit: 1,
},
[]*model.User{u1},
},
{
"search jimb, group 2",
g2.Id,
"jimb",
&model.UserSearchOptions{
AllowFullNames: true,
Limit: model.USER_SEARCH_DEFAULT_LIMIT,
},
[]*model.User{},
},
{
"search jimb, allow inactive, group 2",
g2.Id,
"jimb",
&model.UserSearchOptions{
AllowFullNames: true,
AllowInactive: true,
Limit: model.USER_SEARCH_DEFAULT_LIMIT,
},
[]*model.User{},
},
}
for _, testCase := range testCases {
t.Run(testCase.Description, func(t *testing.T) {
users, err := ss.User().SearchInGroup(
testCase.GroupId,
testCase.Term,
testCase.Options,
)
require.Nil(t, err)
assertUsers(t, testCase.Expected, users)
})
}
}
func testCount(t *testing.T, ss store.Store) {
// Regular
teamId := model.NewId()

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

@@ -7444,6 +7444,22 @@ func (s *TimerLayerUserStore) SearchInChannel(channelId string, term string, opt
return resultVar0, resultVar1
}
func (s *TimerLayerUserStore) SearchInGroup(groupID string, term string, options *model.UserSearchOptions) ([]*model.User, *model.AppError) {
start := timemodule.Now()
resultVar0, resultVar1 := s.UserStore.SearchInGroup(groupID, term, options)
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
if s.Root.Metrics != nil {
success := "false"
if resultVar1 == nil {
success = "true"
}
s.Root.Metrics.ObserveStoreMethodDuration("UserStore.SearchInGroup", success, elapsed)
}
return resultVar0, resultVar1
}
func (s *TimerLayerUserStore) SearchNotInChannel(teamId string, channelId string, term string, options *model.UserSearchOptions) ([]*model.User, *model.AppError) {
start := timemodule.Now()