PLT-6162: Search for users not in a given team. (#5943)
Этот коммит содержится в:
коммит произвёл
Harrison Healey
родитель
da5265681d
Коммит
232a99f0c7
@@ -397,6 +397,11 @@ func searchUsers(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if props.NotInTeamId != "" && !app.SessionHasPermissionToTeam(c.Session, props.NotInTeamId, model.PERMISSION_VIEW_TEAM) {
|
||||||
|
c.SetPermissionError(model.PERMISSION_VIEW_TEAM)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
searchOptions := map[string]bool{}
|
searchOptions := map[string]bool{}
|
||||||
searchOptions[store.USER_SEARCH_OPTION_ALLOW_INACTIVE] = props.AllowInactive
|
searchOptions[store.USER_SEARCH_OPTION_ALLOW_INACTIVE] = props.AllowInactive
|
||||||
|
|
||||||
|
|||||||
@@ -385,6 +385,45 @@ func TestSearchUsers(t *testing.T) {
|
|||||||
_, resp = Client.SearchUsers(search)
|
_, resp = Client.SearchUsers(search)
|
||||||
CheckForbiddenStatus(t, resp)
|
CheckForbiddenStatus(t, resp)
|
||||||
|
|
||||||
|
// Test search for users not in any team
|
||||||
|
search.TeamId = ""
|
||||||
|
search.NotInChannelId = ""
|
||||||
|
search.InChannelId = ""
|
||||||
|
search.NotInTeamId = th.BasicTeam.Id
|
||||||
|
|
||||||
|
users, resp = Client.SearchUsers(search)
|
||||||
|
CheckNoError(t, resp)
|
||||||
|
|
||||||
|
if findUserInList(th.BasicUser.Id, users) {
|
||||||
|
t.Fatal("should not have found user")
|
||||||
|
}
|
||||||
|
|
||||||
|
oddUser := th.CreateUser()
|
||||||
|
search.Term = oddUser.Username
|
||||||
|
|
||||||
|
users, resp = Client.SearchUsers(search)
|
||||||
|
CheckNoError(t, resp)
|
||||||
|
|
||||||
|
if !findUserInList(oddUser.Id, users) {
|
||||||
|
t.Fatal("should have found user")
|
||||||
|
}
|
||||||
|
|
||||||
|
_, resp = th.SystemAdminClient.AddTeamMember(th.BasicTeam.Id, oddUser.Id, "", "", th.BasicTeam.InviteId)
|
||||||
|
CheckNoError(t, resp)
|
||||||
|
|
||||||
|
users, resp = Client.SearchUsers(search)
|
||||||
|
CheckNoError(t, resp)
|
||||||
|
|
||||||
|
if findUserInList(oddUser.Id, users) {
|
||||||
|
t.Fatal("should not have found user")
|
||||||
|
}
|
||||||
|
|
||||||
|
search.NotInTeamId = model.NewId()
|
||||||
|
_, resp = Client.SearchUsers(search)
|
||||||
|
CheckForbiddenStatus(t, resp)
|
||||||
|
|
||||||
|
search.Term = th.BasicUser.Username
|
||||||
|
|
||||||
emailPrivacy := utils.Cfg.PrivacySettings.ShowEmailAddress
|
emailPrivacy := utils.Cfg.PrivacySettings.ShowEmailAddress
|
||||||
namePrivacy := utils.Cfg.PrivacySettings.ShowFullName
|
namePrivacy := utils.Cfg.PrivacySettings.ShowFullName
|
||||||
defer func() {
|
defer func() {
|
||||||
@@ -400,6 +439,7 @@ func TestSearchUsers(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
search.InChannelId = ""
|
search.InChannelId = ""
|
||||||
|
search.NotInTeamId = ""
|
||||||
search.Term = th.BasicUser2.Email
|
search.Term = th.BasicUser2.Email
|
||||||
users, resp = Client.SearchUsers(search)
|
users, resp = Client.SearchUsers(search)
|
||||||
CheckNoError(t, resp)
|
CheckNoError(t, resp)
|
||||||
|
|||||||
16
app/user.go
16
app/user.go
@@ -1299,6 +1299,8 @@ func SearchUsers(props *model.UserSearch, searchOptions map[string]bool, asAdmin
|
|||||||
return SearchUsersInChannel(props.InChannelId, props.Term, searchOptions, asAdmin)
|
return SearchUsersInChannel(props.InChannelId, props.Term, searchOptions, asAdmin)
|
||||||
} else if props.NotInChannelId != "" {
|
} else if props.NotInChannelId != "" {
|
||||||
return SearchUsersNotInChannel(props.TeamId, props.NotInChannelId, props.Term, searchOptions, asAdmin)
|
return SearchUsersNotInChannel(props.TeamId, props.NotInChannelId, props.Term, searchOptions, asAdmin)
|
||||||
|
} else if props.NotInTeamId != "" {
|
||||||
|
return SearchUsersNotInTeam(props.NotInTeamId, props.Term, searchOptions, asAdmin)
|
||||||
} else {
|
} else {
|
||||||
return SearchUsersInTeam(props.TeamId, props.Term, searchOptions, asAdmin)
|
return SearchUsersInTeam(props.TeamId, props.Term, searchOptions, asAdmin)
|
||||||
}
|
}
|
||||||
@@ -1346,6 +1348,20 @@ func SearchUsersInTeam(teamId string, term string, searchOptions map[string]bool
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SearchUsersNotInTeam(notInTeamId string, term string, searchOptions map[string]bool, asAdmin bool) ([]*model.User, *model.AppError) {
|
||||||
|
if result := <-Srv.Store.User().SearchNotInTeam(notInTeamId, term, searchOptions); result.Err != nil {
|
||||||
|
return nil, result.Err
|
||||||
|
} else {
|
||||||
|
users := result.Data.([]*model.User)
|
||||||
|
|
||||||
|
for _, user := range users {
|
||||||
|
SanitizeProfile(user, asAdmin)
|
||||||
|
}
|
||||||
|
|
||||||
|
return users, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func SearchUsersWithoutTeam(term string, searchOptions map[string]bool, asAdmin bool) ([]*model.User, *model.AppError) {
|
func SearchUsersWithoutTeam(term string, searchOptions map[string]bool, asAdmin bool) ([]*model.User, *model.AppError) {
|
||||||
if result := <-Srv.Store.User().SearchWithoutTeam(term, searchOptions); result.Err != nil {
|
if result := <-Srv.Store.User().SearchWithoutTeam(term, searchOptions); result.Err != nil {
|
||||||
return nil, result.Err
|
return nil, result.Err
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
type UserSearch struct {
|
type UserSearch struct {
|
||||||
Term string `json:"term"`
|
Term string `json:"term"`
|
||||||
TeamId string `json:"team_id"`
|
TeamId string `json:"team_id"`
|
||||||
|
NotInTeamId string `json:"not_in_team_id"`
|
||||||
InChannelId string `json:"in_channel_id"`
|
InChannelId string `json:"in_channel_id"`
|
||||||
NotInChannelId string `json:"not_in_channel_id"`
|
NotInChannelId string `json:"not_in_channel_id"`
|
||||||
AllowInactive bool `json:"allow_inactive"`
|
AllowInactive bool `json:"allow_inactive"`
|
||||||
|
|||||||
@@ -1339,6 +1339,32 @@ func (us SqlUserStore) SearchWithoutTeam(term string, options map[string]bool) S
|
|||||||
return storeChannel
|
return storeChannel
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (us SqlUserStore) SearchNotInTeam(notInTeamId string, term string, options map[string]bool) StoreChannel {
|
||||||
|
storeChannel := make(StoreChannel, 1)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
searchQuery := `
|
||||||
|
SELECT
|
||||||
|
Users.*
|
||||||
|
FROM Users
|
||||||
|
LEFT JOIN TeamMembers tm
|
||||||
|
ON tm.UserId = Users.Id
|
||||||
|
AND tm.TeamId = :NotInTeamId
|
||||||
|
WHERE
|
||||||
|
tm.UserId IS NULL
|
||||||
|
SEARCH_CLAUSE
|
||||||
|
INACTIVE_CLAUSE
|
||||||
|
ORDER BY Users.Username ASC
|
||||||
|
LIMIT 100`
|
||||||
|
|
||||||
|
storeChannel <- us.performSearch(searchQuery, term, options, map[string]interface{}{"NotInTeamId": notInTeamId})
|
||||||
|
close(storeChannel)
|
||||||
|
|
||||||
|
}()
|
||||||
|
|
||||||
|
return storeChannel
|
||||||
|
}
|
||||||
|
|
||||||
func (us SqlUserStore) SearchNotInChannel(teamId string, channelId string, term string, options map[string]bool) StoreChannel {
|
func (us SqlUserStore) SearchNotInChannel(teamId string, channelId string, term string, options map[string]bool) StoreChannel {
|
||||||
storeChannel := make(StoreChannel, 1)
|
storeChannel := make(StoreChannel, 1)
|
||||||
|
|
||||||
|
|||||||
@@ -1546,6 +1546,47 @@ func TestUserStoreSearch(t *testing.T) {
|
|||||||
t.Fatal("should have found user")
|
t.Fatal("should have found user")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Search Users not in Team.
|
||||||
|
u4 := &model.User{}
|
||||||
|
u4.Username = "simon" + model.NewId()
|
||||||
|
u4.Email = model.NewId()
|
||||||
|
u4.DeleteAt = 0
|
||||||
|
Must(store.User().Save(u4))
|
||||||
|
|
||||||
|
if r1 := <-store.User().SearchNotInTeam(tid, "simo", searchOptions); r1.Err != nil {
|
||||||
|
t.Fatal(r1.Err)
|
||||||
|
} else {
|
||||||
|
profiles := r1.Data.([]*model.User)
|
||||||
|
found := false
|
||||||
|
for _, profile := range profiles {
|
||||||
|
if profile.Id == u4.Id {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !found {
|
||||||
|
t.Fatal("should have found user")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if r1 := <-store.User().SearchNotInTeam(tid, "jimb", searchOptions); r1.Err != nil {
|
||||||
|
t.Fatal(r1.Err)
|
||||||
|
} else {
|
||||||
|
profiles := r1.Data.([]*model.User)
|
||||||
|
found := false
|
||||||
|
for _, profile := range profiles {
|
||||||
|
if profile.Id == u1.Id {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if found {
|
||||||
|
t.Fatal("should not have found user")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUserStoreSearchWithoutTeam(t *testing.T) {
|
func TestUserStoreSearchWithoutTeam(t *testing.T) {
|
||||||
|
|||||||
@@ -202,6 +202,7 @@ type UserStore interface {
|
|||||||
GetUnreadCountForChannel(userId string, channelId string) StoreChannel
|
GetUnreadCountForChannel(userId string, channelId string) StoreChannel
|
||||||
GetRecentlyActiveUsersForTeam(teamId string) StoreChannel
|
GetRecentlyActiveUsersForTeam(teamId string) StoreChannel
|
||||||
Search(teamId string, term string, options map[string]bool) StoreChannel
|
Search(teamId string, term string, options map[string]bool) StoreChannel
|
||||||
|
SearchNotInTeam(notInTeamId string, term string, options map[string]bool) StoreChannel
|
||||||
SearchInChannel(channelId string, term string, options map[string]bool) StoreChannel
|
SearchInChannel(channelId string, term string, options map[string]bool) StoreChannel
|
||||||
SearchNotInChannel(teamId string, channelId string, term string, options map[string]bool) StoreChannel
|
SearchNotInChannel(teamId string, channelId string, term string, options map[string]bool) StoreChannel
|
||||||
SearchWithoutTeam(term string, options map[string]bool) StoreChannel
|
SearchWithoutTeam(term string, options map[string]bool) StoreChannel
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user