diff options
author | Saturnino Abril <saturnino.abril@gmail.com> | 2017-04-04 02:34:14 +0900 |
---|---|---|
committer | Corey Hulen <corey@hulen.com> | 2017-04-03 10:34:14 -0700 |
commit | 43e795448f62fa86f3dad7940fc2297c44a6ea9c (patch) | |
tree | aec7f651c2177f9cc02824f014bccd81e96c542a | |
parent | 6b61834ab14e9a4e51c29dd2904a1332c327aae6 (diff) | |
download | chat-43e795448f62fa86f3dad7940fc2297c44a6ea9c.tar.gz chat-43e795448f62fa86f3dad7940fc2297c44a6ea9c.tar.bz2 chat-43e795448f62fa86f3dad7940fc2297c44a6ea9c.zip |
APIv4 post /teams/search (#5931)
-rw-r--r-- | api4/team.go | 30 | ||||
-rw-r--r-- | api4/team_test.go | 76 | ||||
-rw-r--r-- | app/team.go | 16 | ||||
-rw-r--r-- | i18n/en.json | 8 | ||||
-rw-r--r-- | model/client4.go | 10 | ||||
-rw-r--r-- | model/team_search.go | 35 | ||||
-rw-r--r-- | model/team_search_test.go | 19 | ||||
-rw-r--r-- | store/sql_team_store.go | 42 | ||||
-rw-r--r-- | store/sql_team_store_test.go | 127 | ||||
-rw-r--r-- | store/store.go | 2 |
10 files changed, 364 insertions, 1 deletions
diff --git a/api4/team.go b/api4/team.go index 85a083ee1..d71ccbf2e 100644 --- a/api4/team.go +++ b/api4/team.go @@ -20,6 +20,7 @@ func InitTeam() { BaseRoutes.Teams.Handle("", ApiSessionRequired(createTeam)).Methods("POST") BaseRoutes.Teams.Handle("", ApiSessionRequired(getAllTeams)).Methods("GET") + BaseRoutes.Teams.Handle("/search", ApiSessionRequired(searchTeams)).Methods("POST") BaseRoutes.TeamsForUser.Handle("", ApiSessionRequired(getTeamsForUser)).Methods("GET") BaseRoutes.TeamsForUser.Handle("/unread", ApiSessionRequired(getTeamsUnreadForUser)).Methods("GET") @@ -456,6 +457,35 @@ func getAllTeams(c *Context, w http.ResponseWriter, r *http.Request) { w.Write([]byte(model.TeamListToJson(teams))) } +func searchTeams(c *Context, w http.ResponseWriter, r *http.Request) { + props := model.TeamSearchFromJson(r.Body) + if props == nil { + c.SetInvalidParam("team_search") + return + } + + if len(props.Term) == 0 { + c.SetInvalidParam("term") + return + } + + var teams []*model.Team + var err *model.AppError + + if app.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) { + teams, err = app.SearchAllTeams(props.Term) + } else { + teams, err = app.SearchOpenTeams(props.Term) + } + + if err != nil { + c.Err = err + return + } + + w.Write([]byte(model.TeamListToJson(teams))) +} + func teamExists(c *Context, w http.ResponseWriter, r *http.Request) { c.RequireTeamName() if c.Err != nil { diff --git a/api4/team_test.go b/api4/team_test.go index 6127919c1..227b0958b 100644 --- a/api4/team_test.go +++ b/api4/team_test.go @@ -7,6 +7,7 @@ import ( "encoding/binary" "fmt" "net/http" + "reflect" "strconv" "strings" "testing" @@ -405,6 +406,81 @@ func TestGetTeamByName(t *testing.T) { CheckForbiddenStatus(t, resp) } +func TestSearchAllTeams(t *testing.T) { + th := Setup().InitBasic().InitSystemAdmin() + defer TearDown() + Client := th.Client + oTeam := th.BasicTeam + + pTeam := &model.Team{DisplayName: "PName", Name: GenerateTestTeamName(), Email: GenerateTestEmail(), Type: model.TEAM_INVITE} + Client.CreateTeam(pTeam) + + rteams, resp := Client.SearchTeams(&model.TeamSearch{Term: oTeam.Name}) + CheckNoError(t, resp) + + if len(rteams) != 1 { + t.Fatal("should have returned 1 team") + } + + if !reflect.DeepEqual(rteams[0], oTeam) { + t.Fatal("invalid team") + } + + rteams, resp = Client.SearchTeams(&model.TeamSearch{Term: oTeam.DisplayName}) + CheckNoError(t, resp) + + if len(rteams) != 1 { + t.Fatal("should have returned 1 team") + } + + if !reflect.DeepEqual(rteams[0], oTeam) { + t.Fatal("invalid team") + } + + rteams, resp = Client.SearchTeams(&model.TeamSearch{Term: pTeam.Name}) + CheckNoError(t, resp) + + if len(rteams) != 0 { + t.Fatal("should have not returned team") + } + + rteams, resp = Client.SearchTeams(&model.TeamSearch{Term: pTeam.DisplayName}) + CheckNoError(t, resp) + + if len(rteams) != 0 { + t.Fatal("should have not returned team") + } + + rteams, resp = th.SystemAdminClient.SearchTeams(&model.TeamSearch{Term: oTeam.Name}) + CheckNoError(t, resp) + + if len(rteams) != 1 { + t.Fatal("should have returned 1 team") + } + + rteams, resp = th.SystemAdminClient.SearchTeams(&model.TeamSearch{Term: pTeam.DisplayName}) + CheckNoError(t, resp) + + if len(rteams) != 1 { + t.Fatal("should have returned 1 team") + } + + rteams, resp = Client.SearchTeams(&model.TeamSearch{Term: "junk"}) + CheckNoError(t, resp) + + if len(rteams) != 0 { + t.Fatal("should have not returned team") + } + + Client.Logout() + + rteams, resp = Client.SearchTeams(&model.TeamSearch{Term: pTeam.Name}) + CheckUnauthorizedStatus(t, resp) + + rteams, resp = Client.SearchTeams(&model.TeamSearch{Term: pTeam.DisplayName}) + CheckUnauthorizedStatus(t, resp) +} + func TestGetTeamsForUser(t *testing.T) { th := Setup().InitBasic().InitSystemAdmin() defer TearDown() diff --git a/app/team.go b/app/team.go index dbff5ffac..9abb7d53e 100644 --- a/app/team.go +++ b/app/team.go @@ -367,6 +367,22 @@ func GetAllOpenTeams() ([]*model.Team, *model.AppError) { } } +func SearchAllTeams(term string) ([]*model.Team, *model.AppError) { + if result := <-Srv.Store.Team().SearchAll(term); result.Err != nil { + return nil, result.Err + } else { + return result.Data.([]*model.Team), nil + } +} + +func SearchOpenTeams(term string) ([]*model.Team, *model.AppError) { + if result := <-Srv.Store.Team().SearchOpen(term); result.Err != nil { + return nil, result.Err + } else { + return result.Data.([]*model.Team), nil + } +} + func GetAllOpenTeamsPage(offset int, limit int) ([]*model.Team, *model.AppError) { if result := <-Srv.Store.Team().GetAllTeamPageListing(offset, limit); result.Err != nil { return nil, result.Err diff --git a/i18n/en.json b/i18n/en.json index 2a9c8309a..aeec957bd 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -5512,6 +5512,14 @@ "translation": "We couldn't save the team member" }, { + "id": "store.sql_team.search_open_team.app_error", + "translation": "We encountered an error searching open teams" + }, + { + "id": "store.sql_team.search_all_team.app_error", + "translation": "We encountered an error searching teams" + }, + { "id": "store.sql_team.update.app_error", "translation": "We couldn't update the team" }, diff --git a/model/client4.go b/model/client4.go index 3d0f19622..0d4c0600e 100644 --- a/model/client4.go +++ b/model/client4.go @@ -842,6 +842,16 @@ func (c *Client4) GetTeamByName(name, etag string) (*Team, *Response) { } } +// SearchTeams returns teams matching the provided search term. +func (c *Client4) SearchTeams(search *TeamSearch) ([]*Team, *Response) { + if r, err := c.DoApiPost(c.GetTeamsRoute()+"/search", search.ToJson()); err != nil { + return nil, &Response{StatusCode: r.StatusCode, Error: err} + } else { + defer closeBody(r) + return TeamListFromJson(r.Body), BuildResponse(r) + } +} + // TeamExists returns true or false if the team exist or not. func (c *Client4) TeamExists(name, etag string) (bool, *Response) { if r, err := c.DoApiGet(c.GetTeamByNameRoute(name)+"/exists", etag); err != nil { diff --git a/model/team_search.go b/model/team_search.go new file mode 100644 index 000000000..4ab30f96b --- /dev/null +++ b/model/team_search.go @@ -0,0 +1,35 @@ +// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package model + +import ( + "encoding/json" + "io" +) + +type TeamSearch struct { + Term string `json:"term"` +} + +// ToJson convert a TeamSearch to json string +func (c *TeamSearch) ToJson() string { + b, err := json.Marshal(c) + if err != nil { + return "" + } + + return string(b) +} + +// TeamSearchFromJson decodes the input and returns a TeamSearch +func TeamSearchFromJson(data io.Reader) *TeamSearch { + decoder := json.NewDecoder(data) + var cs TeamSearch + err := decoder.Decode(&cs) + if err == nil { + return &cs + } + + return nil +} diff --git a/model/team_search_test.go b/model/team_search_test.go new file mode 100644 index 000000000..996adad43 --- /dev/null +++ b/model/team_search_test.go @@ -0,0 +1,19 @@ +// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package model + +import ( + "strings" + "testing" +) + +func TestTeamSearchJson(t *testing.T) { + teamSearch := TeamSearch{Term: NewId()} + json := teamSearch.ToJson() + rteamSearch := ChannelSearchFromJson(strings.NewReader(json)) + + if teamSearch.Term != rteamSearch.Term { + t.Fatal("Terms do not match") + } +} diff --git a/store/sql_team_store.go b/store/sql_team_store.go index 7d843b030..39a39fa0b 100644 --- a/store/sql_team_store.go +++ b/store/sql_team_store.go @@ -257,6 +257,48 @@ func (s SqlTeamStore) SearchByName(name string) StoreChannel { return storeChannel } +func (s SqlTeamStore) SearchAll(term string) StoreChannel { + storeChannel := make(StoreChannel, 1) + + go func() { + result := StoreResult{} + + var teams []*model.Team + + if _, err := s.GetReplica().Select(&teams, "SELECT * FROM Teams WHERE Name LIKE :Term OR DisplayName LIKE :Term", map[string]interface{}{"Term": term + "%"}); err != nil { + result.Err = model.NewLocAppError("SqlTeamStore.SearchAll", "store.sql_team.search_all_team.app_error", nil, "term="+term+", "+err.Error()) + } + + result.Data = teams + + storeChannel <- result + close(storeChannel) + }() + + return storeChannel +} + +func (s SqlTeamStore) SearchOpen(term string) StoreChannel { + storeChannel := make(StoreChannel, 1) + + go func() { + result := StoreResult{} + + var teams []*model.Team + + if _, err := s.GetReplica().Select(&teams, "SELECT * FROM Teams WHERE Type = 'O' AND (Name LIKE :Term OR DisplayName LIKE :Term)", map[string]interface{}{"Term": term + "%"}); err != nil { + result.Err = model.NewLocAppError("SqlTeamStore.SearchOpen", "store.sql_team.search_open_team.app_error", nil, "term="+term+", "+err.Error()) + } + + result.Data = teams + + storeChannel <- result + close(storeChannel) + }() + + return storeChannel +} + func (s SqlTeamStore) GetAll() StoreChannel { storeChannel := make(StoreChannel, 1) diff --git a/store/sql_team_store_test.go b/store/sql_team_store_test.go index 3aeb14c9c..3599a6d1a 100644 --- a/store/sql_team_store_test.go +++ b/store/sql_team_store_test.go @@ -4,9 +4,10 @@ package store import ( - "github.com/mattermost/platform/model" "testing" "time" + + "github.com/mattermost/platform/model" ) func TestTeamStoreSave(t *testing.T) { @@ -156,6 +157,130 @@ func TestTeamStoreSearchByName(t *testing.T) { } } +func TestTeamStoreSearchAll(t *testing.T) { + Setup() + + o1 := model.Team{} + o1.DisplayName = "ADisplayName" + model.NewId() + o1.Name = "a" + model.NewId() + "a" + o1.Email = model.NewId() + "@nowhere.com" + o1.Type = model.TEAM_OPEN + + if err := (<-store.Team().Save(&o1)).Err; err != nil { + t.Fatal(err) + } + + p2 := model.Team{} + p2.DisplayName = "BDisplayName" + model.NewId() + p2.Name = "b" + model.NewId() + "b" + p2.Email = model.NewId() + "@nowhere.com" + p2.Type = model.TEAM_INVITE + + if err := (<-store.Team().Save(&p2)).Err; err != nil { + t.Fatal(err) + } + + r1 := <-store.Team().SearchAll(o1.Name) + if r1.Err != nil { + t.Fatal(r1.Err) + } + if len(r1.Data.([]*model.Team)) != 1 { + t.Fatal("should have returned 1 team") + } + if r1.Data.([]*model.Team)[0].ToJson() != o1.ToJson() { + t.Fatal("invalid returned team") + } + + r1 = <-store.Team().SearchAll(p2.DisplayName) + if r1.Err != nil { + t.Fatal(r1.Err) + } + if len(r1.Data.([]*model.Team)) != 1 { + t.Fatal("should have returned 1 team") + } + if r1.Data.([]*model.Team)[0].ToJson() != p2.ToJson() { + t.Fatal("invalid returned team") + } + + r1 = <-store.Team().SearchAll("junk") + if r1.Err != nil { + t.Fatal(r1.Err) + } + if len(r1.Data.([]*model.Team)) != 0 { + t.Fatal("should have not returned a team") + } +} + +func TestTeamStoreSearchOpen(t *testing.T) { + Setup() + + o1 := model.Team{} + o1.DisplayName = "ADisplayName" + model.NewId() + o1.Name = "a" + model.NewId() + "a" + o1.Email = model.NewId() + "@nowhere.com" + o1.Type = model.TEAM_OPEN + + if err := (<-store.Team().Save(&o1)).Err; err != nil { + t.Fatal(err) + } + + p2 := model.Team{} + p2.DisplayName = "BDisplayName" + model.NewId() + p2.Name = "b" + model.NewId() + "b" + p2.Email = model.NewId() + "@nowhere.com" + p2.Type = model.TEAM_INVITE + + if err := (<-store.Team().Save(&p2)).Err; err != nil { + t.Fatal(err) + } + + r1 := <-store.Team().SearchOpen(o1.Name) + if r1.Err != nil { + t.Fatal(r1.Err) + } + if len(r1.Data.([]*model.Team)) != 1 { + t.Fatal("should have returned 1 team") + } + if r1.Data.([]*model.Team)[0].ToJson() != o1.ToJson() { + t.Fatal("invalid returned team") + } + + r1 = <-store.Team().SearchOpen(o1.DisplayName) + if r1.Err != nil { + t.Fatal(r1.Err) + } + if len(r1.Data.([]*model.Team)) != 1 { + t.Fatal("should have returned 1 team") + } + if r1.Data.([]*model.Team)[0].ToJson() != o1.ToJson() { + t.Fatal("invalid returned team") + } + + r1 = <-store.Team().SearchOpen(p2.Name) + if r1.Err != nil { + t.Fatal(r1.Err) + } + if len(r1.Data.([]*model.Team)) != 0 { + t.Fatal("should have not returned a team") + } + + r1 = <-store.Team().SearchOpen(p2.DisplayName) + if r1.Err != nil { + t.Fatal(r1.Err) + } + if len(r1.Data.([]*model.Team)) != 0 { + t.Fatal("should have not returned a team") + } + + r1 = <-store.Team().SearchOpen("junk") + if r1.Err != nil { + t.Fatal(r1.Err) + } + if len(r1.Data.([]*model.Team)) != 0 { + t.Fatal("should have not returned a team") + } +} + func TestTeamStoreGetByIniviteId(t *testing.T) { Setup() diff --git a/store/store.go b/store/store.go index de70edb99..3e508dfa5 100644 --- a/store/store.go +++ b/store/store.go @@ -61,6 +61,8 @@ type TeamStore interface { Get(id string) StoreChannel GetByName(name string) StoreChannel SearchByName(name string) StoreChannel + SearchAll(term string) StoreChannel + SearchOpen(term string) StoreChannel GetAll() StoreChannel GetAllPage(offset int, limit int) StoreChannel GetAllTeamListing() StoreChannel |