API for getting channel members by IDs. (#4877)

Этот коммит содержится в:
George Goldberg
2016-12-22 18:21:05 +00:00
коммит произвёл Corey Hulen
родитель b79b2b2a53
Коммит 53847af2c4
7 изменённых файлов: 159 добавлений и 0 удалений

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

@@ -39,6 +39,7 @@ func InitChannel() {
BaseRoutes.NeedChannel.Handle("/", ApiUserRequired(getChannel)).Methods("GET") BaseRoutes.NeedChannel.Handle("/", ApiUserRequired(getChannel)).Methods("GET")
BaseRoutes.NeedChannel.Handle("/stats", ApiUserRequired(getChannelStats)).Methods("GET") BaseRoutes.NeedChannel.Handle("/stats", ApiUserRequired(getChannelStats)).Methods("GET")
BaseRoutes.NeedChannel.Handle("/members/{user_id:[A-Za-z0-9]+}", ApiUserRequired(getChannelMember)).Methods("GET") BaseRoutes.NeedChannel.Handle("/members/{user_id:[A-Za-z0-9]+}", ApiUserRequired(getChannelMember)).Methods("GET")
BaseRoutes.NeedChannel.Handle("/members/ids", ApiUserRequired(getChannelMembersByIds)).Methods("POST")
BaseRoutes.NeedChannel.Handle("/join", ApiUserRequired(join)).Methods("POST") BaseRoutes.NeedChannel.Handle("/join", ApiUserRequired(join)).Methods("POST")
BaseRoutes.NeedChannel.Handle("/leave", ApiUserRequired(leave)).Methods("POST") BaseRoutes.NeedChannel.Handle("/leave", ApiUserRequired(leave)).Methods("POST")
BaseRoutes.NeedChannel.Handle("/delete", ApiUserRequired(deleteChannel)).Methods("POST") BaseRoutes.NeedChannel.Handle("/delete", ApiUserRequired(deleteChannel)).Methods("POST")
@@ -1300,3 +1301,27 @@ func viewChannel(c *Context, w http.ResponseWriter, r *http.Request) {
ReturnStatusOK(w) ReturnStatusOK(w)
} }
func getChannelMembersByIds(c *Context, w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
channelId := params["channel_id"]
userIds := model.ArrayFromJson(r.Body)
if len(userIds) == 0 {
c.SetInvalidParam("getChannelMembersByIds", "user_ids")
return
}
if !HasPermissionToChannelContext(c, channelId, model.PERMISSION_READ_CHANNEL) {
return
}
if result := <-Srv.Store.Channel().GetMembersByIds(channelId, userIds); result.Err != nil {
c.Err = result.Err
return
} else {
members := result.Data.(model.ChannelMembers)
w.Write([]byte(members.ToJson()))
return
}
}

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

@@ -1777,3 +1777,40 @@ func TestViewChannel(t *testing.T) {
t.Fatal("message counts don't match") t.Fatal("message counts don't match")
} }
} }
func TestGetChannelMembersByIds(t *testing.T) {
th := Setup().InitBasic()
if _, err := AddUserToChannel(th.BasicUser2, th.BasicChannel); err != nil {
t.Fatal("Could not add second user to channel")
}
if result, err := th.BasicClient.GetChannelMembersByIds(th.BasicChannel.Id, []string{th.BasicUser.Id}); err != nil {
t.Fatal(err)
} else {
member := (*result.Data.(*model.ChannelMembers))[0]
if member.UserId != th.BasicUser.Id {
t.Fatal("user id did not match")
}
if member.ChannelId != th.BasicChannel.Id {
t.Fatal("team id did not match")
}
}
if result, err := th.BasicClient.GetChannelMembersByIds(th.BasicChannel.Id, []string{th.BasicUser.Id, th.BasicUser2.Id, model.NewId()}); err != nil {
t.Fatal(err)
} else {
members := result.Data.(*model.ChannelMembers)
if len(*members) != 2 {
t.Fatal("length should have been 2, got ", len(*members))
}
}
if _, err := th.BasicClient.GetChannelMembersByIds("junk", []string{th.BasicUser.Id}); err == nil {
t.Fatal("should have errored - bad team id")
}
if _, err := th.BasicClient.GetChannelMembersByIds(th.BasicChannel.Id, []string{}); err == nil {
t.Fatal("should have errored - empty user ids")
}
}

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

@@ -4175,6 +4175,10 @@
"id": "store.sql_channel.get.find.app_error", "id": "store.sql_channel.get.find.app_error",
"translation": "We encountered an error finding the channel" "translation": "We encountered an error finding the channel"
}, },
{
"id": "store.sql_channel.get_members_by_ids.app_error",
"translation": "We couldn't get the channel members"
},
{ {
"id": "store.sql_channel.get_all.app_error", "id": "store.sql_channel.get_all.app_error",
"translation": "We couldn't get all the channels" "translation": "We couldn't get all the channels"

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

@@ -1387,6 +1387,18 @@ func (c *Client) GetChannelMember(channelId string, userId string) (*Result, *Ap
} }
} }
// GetChannelMembersByIds will return channel member objects as an array based on the
// channel id and a list of user ids provided. Must be authenticated.
func (c *Client) GetChannelMembersByIds(channelId string, userIds []string) (*Result, *AppError) {
if r, err := c.DoApiPost(c.GetChannelRoute(channelId)+"/members/ids", ArrayToJson(userIds)); err != nil {
return nil, err
} else {
defer closeBody(r)
return &Result{r.Header.Get(HEADER_REQUEST_ID),
r.Header.Get(HEADER_ETAG_SERVER), ChannelMembersFromJson(r.Body)}, nil
}
}
func (c *Client) CreatePost(post *Post) (*Result, *AppError) { func (c *Client) CreatePost(post *Post) (*Result, *AppError) {
if r, err := c.DoApiPost(c.GetChannelRoute(post.ChannelId)+"/posts/create", post.ToJson()); err != nil { if r, err := c.DoApiPost(c.GetChannelRoute(post.ChannelId)+"/posts/create", post.ToJson()); err != nil {
return nil, err return nil, err

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

@@ -13,6 +13,7 @@ import (
"github.com/mattermost/platform/einterfaces" "github.com/mattermost/platform/einterfaces"
"github.com/mattermost/platform/model" "github.com/mattermost/platform/model"
"github.com/mattermost/platform/utils" "github.com/mattermost/platform/utils"
"strconv"
) )
const ( const (
@@ -1270,3 +1271,37 @@ func (s SqlChannelStore) performSearch(searchQuery string, term string, paramete
return result return result
} }
func (s SqlChannelStore) GetMembersByIds(channelId string, userIds []string) StoreChannel {
storeChannel := make(StoreChannel, 1)
go func() {
result := StoreResult{}
var members model.ChannelMembers
props := make(map[string]interface{})
idQuery := ""
for index, userId := range userIds {
if len(idQuery) > 0 {
idQuery += ", "
}
props["userId"+strconv.Itoa(index)] = userId
idQuery += ":userId" + strconv.Itoa(index)
}
props["ChannelId"] = channelId
if _, err := s.GetReplica().Select(&members, "SELECT * FROM ChannelMembers WHERE ChannelId = :ChannelId AND UserId IN ("+idQuery+")", props); err != nil {
result.Err = model.NewLocAppError("SqlChannelStore.GetMembersByIds", "store.sql_channel.get_members_by_ids.app_error", nil, "channelId="+channelId+" "+err.Error())
} else {
result.Data = members
}
storeChannel <- result
close(storeChannel)
}()
return storeChannel
}

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

@@ -1280,3 +1280,48 @@ func TestChannelStoreSearchInTeam(t *testing.T) {
} }
} }
} }
func TestChannelStoreGetMembersByIds(t *testing.T) {
Setup()
o1 := model.Channel{}
o1.TeamId = model.NewId()
o1.DisplayName = "ChannelA"
o1.Name = "a" + model.NewId() + "b"
o1.Type = model.CHANNEL_OPEN
Must(store.Channel().Save(&o1))
m1 := &model.ChannelMember{ChannelId: o1.Id, UserId: model.NewId(), NotifyProps: model.GetDefaultChannelNotifyProps()}
Must(store.Channel().SaveMember(m1))
if r := <-store.Channel().GetMembersByIds(m1.ChannelId, []string{m1.UserId}); r.Err != nil {
t.Fatal(r.Err)
} else {
rm1 := r.Data.(model.ChannelMembers)[0]
if rm1.ChannelId != m1.ChannelId {
t.Fatal("bad team id")
}
if rm1.UserId != m1.UserId {
t.Fatal("bad user id")
}
}
m2 := &model.ChannelMember{ChannelId: o1.Id, UserId: model.NewId(), NotifyProps: model.GetDefaultChannelNotifyProps()}
Must(store.Channel().SaveMember(m2))
if r := <-store.Channel().GetMembersByIds(m1.ChannelId, []string{m1.UserId, m2.UserId, model.NewId()}); r.Err != nil {
t.Fatal(r.Err)
} else {
rm := r.Data.(model.ChannelMembers)
if len(rm) != 2 {
t.Fatal("return wrong number of results")
}
}
if r := <-store.Channel().GetMembersByIds(m1.ChannelId, []string{}); r.Err == nil {
t.Fatal("empty user ids - should have failed")
}
}

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

@@ -118,6 +118,7 @@ type ChannelStore interface {
GetMembersForUser(teamId string, userId string) StoreChannel GetMembersForUser(teamId string, userId string) StoreChannel
SearchInTeam(teamId string, term string) StoreChannel SearchInTeam(teamId string, term string) StoreChannel
SearchMore(userId string, teamId string, term string) StoreChannel SearchMore(userId string, teamId string, term string) StoreChannel
GetMembersByIds(channelId string, userIds []string) StoreChannel
} }
type PostStore interface { type PostStore interface {