[MM-13746] Add GetTeamMembersForUser and GetChannelMembersForUser apis (#10269)

* Add GetTeamMembersForUser and GetChannelMembersForUser apis

* Address comments

* Fix tests

* Fix test

* Fix comment

* Fix minimum server version

* Change to []*model.ChannelMember

* Fix panic, add more tests

* Remove print statement
Этот коммит содержится в:
Shobhit Gupta
2019-02-23 11:41:19 -08:00
коммит произвёл Lev
родитель 0e50ec6a35
Коммит b4d645f121
15 изменённых файлов: 373 добавлений и 0 удалений

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

@@ -1207,6 +1207,22 @@ func (a *App) GetChannelMembersForUser(teamId string, userId string) (*model.Cha
return result.Data.(*model.ChannelMembers), nil
}
func (a *App) GetChannelMembersForUserWithPagination(teamId, userId string, page, perPage int) ([]*model.ChannelMember, *model.AppError) {
result := <-a.Srv.Store.Channel().GetMembersForUserWithPagination(teamId, userId, page, perPage)
if result.Err != nil {
return nil, result.Err
}
m := result.Data.(*model.ChannelMembers)
members := make([]*model.ChannelMember, 0)
if m != nil {
for _, member := range *m {
members = append(members, &member)
}
}
return members, nil
}
func (a *App) GetChannelMemberCount(channelId string) (int64, *model.AppError) {
result := <-a.Srv.Store.Channel().GetMemberCount(channelId, true)
if result.Err != nil {

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

@@ -158,6 +158,10 @@ func (api *PluginAPI) GetTeamMember(teamId, userId string) (*model.TeamMember, *
return api.app.GetTeamMember(teamId, userId)
}
func (api *PluginAPI) GetTeamMembersForUser(userId string, page int, perPage int) ([]*model.TeamMember, *model.AppError) {
return api.app.GetTeamMembersForUserWithPagination(userId, page, perPage)
}
func (api *PluginAPI) UpdateTeamMemberRoles(teamId, userId, newRoles string) (*model.TeamMember, *model.AppError) {
return api.app.UpdateTeamMemberRoles(teamId, userId, newRoles)
}
@@ -375,6 +379,10 @@ func (api *PluginAPI) GetChannelMembersByIds(channelId string, userIds []string)
return api.app.GetChannelMembersByIds(channelId, userIds)
}
func (api *PluginAPI) GetChannelMembersForUser(teamId, userId string, page, perPage int) ([]*model.ChannelMember, *model.AppError) {
return api.app.GetChannelMembersForUserWithPagination(teamId, userId, page, perPage)
}
func (api *PluginAPI) UpdateChannelMemberRoles(channelId, userId, newRoles string) (*model.ChannelMember, *model.AppError) {
return api.app.UpdateChannelMemberRoles(channelId, userId, newRoles)
}

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

@@ -881,3 +881,30 @@ func TestPluginAPI_SearchTeams(t *testing.T) {
assert.Empty(t, teams)
})
}
func TestPluginAPI_GetTeamMembersForUser(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
api := th.SetupPluginAPI()
userId := th.BasicUser.Id
teamMembers, err := api.GetTeamMembersForUser(userId, 0, 10)
assert.Nil(t, err)
assert.Equal(t, len(teamMembers), 1)
assert.Equal(t, teamMembers[0].TeamId, th.BasicTeam.Id)
assert.Equal(t, teamMembers[0].UserId, th.BasicUser.Id)
}
func TestPluginAPI_GetChannelMembersForUser(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
api := th.SetupPluginAPI()
userId := th.BasicUser.Id
teamId := th.BasicTeam.Id
channelMembers, err := api.GetChannelMembersForUser(teamId, userId, 0, 10)
assert.Nil(t, err)
assert.Equal(t, len(channelMembers), 3)
assert.Equal(t, channelMembers[0].UserId, th.BasicUser.Id)
}

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

@@ -590,6 +590,14 @@ func (a *App) GetTeamMembersForUser(userId string) ([]*model.TeamMember, *model.
return result.Data.([]*model.TeamMember), nil
}
func (a *App) GetTeamMembersForUserWithPagination(userId string, page, perPage int) ([]*model.TeamMember, *model.AppError) {
result := <-a.Srv.Store.Team().GetTeamsForUserWithPagination(userId, page, perPage)
if result.Err != nil {
return nil, result.Err
}
return result.Data.([]*model.TeamMember), nil
}
func (a *App) GetTeamMembers(teamId string, offset int, limit int) ([]*model.TeamMember, *model.AppError) {
result := <-a.Srv.Store.Team().GetMembers(teamId, offset, limit)
if result.Err != nil {

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

@@ -174,6 +174,11 @@ type API interface {
// GetTeamMember returns a specific membership.
GetTeamMember(teamId, userId string) (*model.TeamMember, *model.AppError)
// GetTeamMembersForUser returns all team memberships for a user.
//
// Minimum server version: 5.10
GetTeamMembersForUser(userId string, page int, perPage int) ([]*model.TeamMember, *model.AppError)
// UpdateTeamMemberRoles updates the role for a team membership.
UpdateTeamMemberRoles(teamId, userId, newRoles string) (*model.TeamMember, *model.AppError)
@@ -247,6 +252,11 @@ type API interface {
// Minimum server version: 5.6
GetChannelMembersByIds(channelId string, userIds []string) (*model.ChannelMembers, *model.AppError)
// GetChannelMembersForUser returns all channel memberships on a team for a user.
//
// Minimum server version: 5.10
GetChannelMembersForUser(teamId, userId string, page, perPage int) ([]*model.ChannelMember, *model.AppError)
// UpdateChannelMemberRoles updates a user's roles for a channel.
UpdateChannelMemberRoles(channelId, userId, newRoles string) (*model.ChannelMember, *model.AppError)

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

@@ -1636,6 +1636,37 @@ func (s *apiRPCServer) GetTeamMember(args *Z_GetTeamMemberArgs, returns *Z_GetTe
return nil
}
type Z_GetTeamMembersForUserArgs struct {
A string
B int
C int
}
type Z_GetTeamMembersForUserReturns struct {
A []*model.TeamMember
B *model.AppError
}
func (g *apiRPCClient) GetTeamMembersForUser(userId string, page int, perPage int) ([]*model.TeamMember, *model.AppError) {
_args := &Z_GetTeamMembersForUserArgs{userId, page, perPage}
_returns := &Z_GetTeamMembersForUserReturns{}
if err := g.client.Call("Plugin.GetTeamMembersForUser", _args, _returns); err != nil {
log.Printf("RPC call to GetTeamMembersForUser API failed: %s", err.Error())
}
return _returns.A, _returns.B
}
func (s *apiRPCServer) GetTeamMembersForUser(args *Z_GetTeamMembersForUserArgs, returns *Z_GetTeamMembersForUserReturns) error {
if hook, ok := s.impl.(interface {
GetTeamMembersForUser(userId string, page int, perPage int) ([]*model.TeamMember, *model.AppError)
}); ok {
returns.A, returns.B = hook.GetTeamMembersForUser(args.A, args.B, args.C)
} else {
return encodableError(fmt.Errorf("API GetTeamMembersForUser called but not implemented."))
}
return nil
}
type Z_UpdateTeamMemberRolesArgs struct {
A string
B string
@@ -2204,6 +2235,38 @@ func (s *apiRPCServer) GetChannelMembersByIds(args *Z_GetChannelMembersByIdsArgs
return nil
}
type Z_GetChannelMembersForUserArgs struct {
A string
B string
C int
D int
}
type Z_GetChannelMembersForUserReturns struct {
A []*model.ChannelMember
B *model.AppError
}
func (g *apiRPCClient) GetChannelMembersForUser(teamId, userId string, page, perPage int) ([]*model.ChannelMember, *model.AppError) {
_args := &Z_GetChannelMembersForUserArgs{teamId, userId, page, perPage}
_returns := &Z_GetChannelMembersForUserReturns{}
if err := g.client.Call("Plugin.GetChannelMembersForUser", _args, _returns); err != nil {
log.Printf("RPC call to GetChannelMembersForUser API failed: %s", err.Error())
}
return _returns.A, _returns.B
}
func (s *apiRPCServer) GetChannelMembersForUser(args *Z_GetChannelMembersForUserArgs, returns *Z_GetChannelMembersForUserReturns) error {
if hook, ok := s.impl.(interface {
GetChannelMembersForUser(teamId, userId string, page, perPage int) ([]*model.ChannelMember, *model.AppError)
}); ok {
returns.A, returns.B = hook.GetChannelMembersForUser(args.A, args.B, args.C, args.D)
} else {
return encodableError(fmt.Errorf("API GetChannelMembersForUser called but not implemented."))
}
return nil
}
type Z_UpdateChannelMemberRolesArgs struct {
A string
B string

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

@@ -515,6 +515,31 @@ func (_m *API) GetChannelMembersByIds(channelId string, userIds []string) (*mode
return r0, r1
}
// GetChannelMembersForUser provides a mock function with given fields: teamId, userId, page, perPage
func (_m *API) GetChannelMembersForUser(teamId string, userId string, page int, perPage int) ([]*model.ChannelMember, *model.AppError) {
ret := _m.Called(teamId, userId, page, perPage)
var r0 []*model.ChannelMember
if rf, ok := ret.Get(0).(func(string, string, int, int) []*model.ChannelMember); ok {
r0 = rf(teamId, userId, page, perPage)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]*model.ChannelMember)
}
}
var r1 *model.AppError
if rf, ok := ret.Get(1).(func(string, string, int, int) *model.AppError); ok {
r1 = rf(teamId, userId, page, perPage)
} else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)
}
}
return r0, r1
}
// GetChannelStats provides a mock function with given fields: channelId
func (_m *API) GetChannelStats(channelId string) (*model.ChannelStats, *model.AppError) {
ret := _m.Called(channelId)
@@ -1291,6 +1316,31 @@ func (_m *API) GetTeamMembers(teamId string, page int, perPage int) ([]*model.Te
return r0, r1
}
// GetTeamMembersForUser provides a mock function with given fields: userId, page, perPage
func (_m *API) GetTeamMembersForUser(userId string, page int, perPage int) ([]*model.TeamMember, *model.AppError) {
ret := _m.Called(userId, page, perPage)
var r0 []*model.TeamMember
if rf, ok := ret.Get(0).(func(string, int, int) []*model.TeamMember); ok {
r0 = rf(userId, page, perPage)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]*model.TeamMember)
}
}
var r1 *model.AppError
if rf, ok := ret.Get(1).(func(string, int, int) *model.AppError); ok {
r1 = rf(userId, page, perPage)
} else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)
}
}
return r0, r1
}
// GetTeamStats provides a mock function with given fields: teamId
func (_m *API) GetTeamStats(teamId string) (*model.TeamStats, *model.AppError) {
ret := _m.Called(teamId)

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

@@ -1923,6 +1923,21 @@ func (s SqlChannelStore) GetMembersForUser(teamId string, userId string) store.S
})
}
func (s SqlChannelStore) GetMembersForUserWithPagination(teamId, userId string, page, perPage int) store.StoreChannel {
return store.Do(func(result *store.StoreResult) {
var dbMembers channelMemberWithSchemeRolesList
offset := page * perPage
_, err := s.GetReplica().Select(&dbMembers, CHANNEL_MEMBERS_WITH_SCHEME_SELECT_QUERY+"WHERE ChannelMembers.UserId = :UserId Limit :Limit Offset :Offset", map[string]interface{}{"TeamId": teamId, "UserId": userId, "Limit": perPage, "Offset": offset})
if err != nil {
result.Err = model.NewAppError("SqlChannelStore.GetMembersForUserWithPagination", "store.sql_channel.get_members.app_error", nil, "teamId="+teamId+", userId="+userId+", err="+err.Error(), http.StatusInternalServerError)
return
}
result.Data = dbMembers.ToModel()
})
}
func (s SqlChannelStore) AutocompleteInTeam(teamId string, term string, includeDeleted bool) store.StoreChannel {
return store.Do(func(result *store.StoreResult) {
deleteFilter := "AND c.DeleteAt = 0"

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

@@ -670,6 +670,20 @@ func (s SqlTeamStore) GetTeamsForUser(userId string) store.StoreChannel {
})
}
func (s SqlTeamStore) GetTeamsForUserWithPagination(userId string, page, perPage int) store.StoreChannel {
return store.Do(func(result *store.StoreResult) {
var dbMembers teamMemberWithSchemeRolesList
offset := page * perPage
_, err := s.GetReplica().Select(&dbMembers, TEAM_MEMBERS_WITH_SCHEME_SELECT_QUERY+"WHERE TeamMembers.UserId = :UserId Limit :Limit Offset :Offset", map[string]interface{}{"UserId": userId, "Limit": perPage, "Offset": offset})
if err != nil {
result.Err = model.NewAppError("SqlTeamStore.GetTeamsForUserWithPagination", "store.sql_team.get_members.app_error", nil, "userId="+userId+" "+err.Error(), http.StatusInternalServerError)
return
}
result.Data = dbMembers.ToModel()
})
}
func (s SqlTeamStore) GetChannelUnreadsForAllTeams(excludeTeamId, userId string) store.StoreChannel {
return store.Do(func(result *store.StoreResult) {
var data []*model.ChannelUnread

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

@@ -104,6 +104,7 @@ type TeamStore interface {
GetTotalMemberCount(teamId string) StoreChannel
GetActiveMemberCount(teamId string) StoreChannel
GetTeamsForUser(userId string) StoreChannel
GetTeamsForUserWithPagination(userId string, page, perPage int) StoreChannel
GetChannelUnreadsForAllTeams(excludeTeamId, userId string) StoreChannel
GetChannelUnreadsForTeam(teamId, userId string) StoreChannel
RemoveMember(teamId string, userId string) StoreChannel
@@ -169,6 +170,7 @@ type ChannelStore interface {
IncrementMentionCount(channelId string, userId string) StoreChannel
AnalyticsTypeCount(teamId string, channelType string) StoreChannel
GetMembersForUser(teamId string, userId string) StoreChannel
GetMembersForUserWithPagination(teamId, userId string, page, perPage int) StoreChannel
AutocompleteInTeam(teamId string, term string, includeDeleted bool) StoreChannel
AutocompleteInTeamForSearch(teamId string, userId string, term string, includeDeleted bool) StoreChannel
SearchAllChannels(term string, includeDeleted bool) StoreChannel

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

@@ -57,6 +57,7 @@ func TestChannelStore(t *testing.T, ss store.Store, s SqlSupplier) {
t.Run("GetPublicChannelsByIdsForTeam", func(t *testing.T) { testChannelStoreGetPublicChannelsByIdsForTeam(t, ss) })
t.Run("GetChannelCounts", func(t *testing.T) { testChannelStoreGetChannelCounts(t, ss) })
t.Run("GetMembersForUser", func(t *testing.T) { testChannelStoreGetMembersForUser(t, ss) })
t.Run("GetMembersForUserWithPagination", func(t *testing.T) { testChannelStoreGetMembersForUserWithPagination(t, ss) })
t.Run("UpdateLastViewedAt", func(t *testing.T) { testChannelStoreUpdateLastViewedAt(t, ss) })
t.Run("IncrementMentionCount", func(t *testing.T) { testChannelStoreIncrementMentionCount(t, ss) })
t.Run("UpdateChannelMember", func(t *testing.T) { testUpdateChannelMember(t, ss) })
@@ -1419,6 +1420,50 @@ func testChannelStoreGetMembersForUser(t *testing.T, ss store.Store) {
}
}
func testChannelStoreGetMembersForUserWithPagination(t *testing.T, ss store.Store) {
t1 := model.Team{}
t1.DisplayName = "Name"
t1.Name = model.NewId()
t1.Email = MakeEmail()
t1.Type = model.TEAM_OPEN
store.Must(ss.Team().Save(&t1))
o1 := model.Channel{}
o1.TeamId = t1.Id
o1.DisplayName = "Channel1"
o1.Name = "zz" + model.NewId() + "b"
o1.Type = model.CHANNEL_OPEN
store.Must(ss.Channel().Save(&o1, -1))
o2 := model.Channel{}
o2.TeamId = o1.TeamId
o2.DisplayName = "Channel2"
o2.Name = "zz" + model.NewId() + "b"
o2.Type = model.CHANNEL_OPEN
store.Must(ss.Channel().Save(&o2, -1))
m1 := model.ChannelMember{}
m1.ChannelId = o1.Id
m1.UserId = model.NewId()
m1.NotifyProps = model.GetDefaultChannelNotifyProps()
store.Must(ss.Channel().SaveMember(&m1))
m2 := model.ChannelMember{}
m2.ChannelId = o2.Id
m2.UserId = m1.UserId
m2.NotifyProps = model.GetDefaultChannelNotifyProps()
store.Must(ss.Channel().SaveMember(&m2))
cresult := <-ss.Channel().GetMembersForUserWithPagination(o1.TeamId, m1.UserId, 0, 1)
members := cresult.Data.(*model.ChannelMembers)
assert.Len(t, *members, 1)
cresult = <-ss.Channel().GetMembersForUserWithPagination(o1.TeamId, m1.UserId, 1, 1)
members = cresult.Data.(*model.ChannelMembers)
assert.Len(t, *members, 1)
}
func testChannelStoreUpdateLastViewedAt(t *testing.T, ss store.Store) {
o1 := model.Channel{}
o1.TeamId = model.NewId()

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

@@ -544,6 +544,22 @@ func (_m *ChannelStore) GetMembersForUser(teamId string, userId string) store.St
return r0
}
// GetMembersForUserWithPagination provides a mock function with given fields: teamId, userId, page, perPage
func (_m *ChannelStore) GetMembersForUserWithPagination(teamId string, userId string, page int, perPage int) store.StoreChannel {
ret := _m.Called(teamId, userId, page, perPage)
var r0 store.StoreChannel
if rf, ok := ret.Get(0).(func(string, string, int, int) store.StoreChannel); ok {
r0 = rf(teamId, userId, page, perPage)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.StoreChannel)
}
}
return r0
}
// GetMoreChannels provides a mock function with given fields: teamId, userId, offset, limit
func (_m *ChannelStore) GetMoreChannels(teamId string, userId string, offset int, limit int) store.StoreChannel {
ret := _m.Called(teamId, userId, offset, limit)

26
store/storetest/mocks/JSONSerializable.go Обычный файл
Просмотреть файл

@@ -0,0 +1,26 @@
// Code generated by mockery v1.0.0. DO NOT EDIT.
// Regenerate this file using `make store-mocks`.
package mocks
import mock "github.com/stretchr/testify/mock"
// JSONSerializable is an autogenerated mock type for the JSONSerializable type
type JSONSerializable struct {
mock.Mock
}
// ToJson provides a mock function with given fields:
func (_m *JSONSerializable) ToJson() string {
ret := _m.Called()
var r0 string
if rf, ok := ret.Get(0).(func() string); ok {
r0 = rf()
} else {
r0 = ret.Get(0).(string)
}
return r0
}

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

@@ -349,6 +349,22 @@ func (_m *TeamStore) GetTeamsForUser(userId string) store.StoreChannel {
return r0
}
// GetTeamsForUserWithPagination provides a mock function with given fields: userId, page, perPage
func (_m *TeamStore) GetTeamsForUserWithPagination(userId string, page int, perPage int) store.StoreChannel {
ret := _m.Called(userId, page, perPage)
var r0 store.StoreChannel
if rf, ok := ret.Get(0).(func(string, int, int) store.StoreChannel); ok {
r0 = rf(userId, page, perPage)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.StoreChannel)
}
}
return r0
}
// GetTotalMemberCount provides a mock function with given fields: teamId
func (_m *TeamStore) GetTotalMemberCount(teamId string) store.StoreChannel {
ret := _m.Called(teamId)

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

@@ -47,6 +47,7 @@ func TestTeamStore(t *testing.T, ss store.Store) {
t.Run("AnalyticsGetTeamCountForScheme", func(t *testing.T) { testTeamStoreAnalyticsGetTeamCountForScheme(t, ss) })
t.Run("GetAllForExportAfter", func(t *testing.T) { testTeamStoreGetAllForExportAfter(t, ss) })
t.Run("GetTeamMembersForExport", func(t *testing.T) { testTeamStoreGetTeamMembersForExport(t, ss) })
t.Run("GetTeamsForUserWithPagination", func(t *testing.T) { testTeamMembersWithPagination(t, ss) })
}
func testTeamStoreSave(t *testing.T, ss store.Store) {
@@ -668,6 +669,62 @@ func testTeamMembers(t *testing.T, ss store.Store) {
}
}
func testTeamMembersWithPagination(t *testing.T, ss store.Store) {
teamId1 := model.NewId()
teamId2 := model.NewId()
m1 := &model.TeamMember{TeamId: teamId1, UserId: model.NewId()}
m2 := &model.TeamMember{TeamId: teamId1, UserId: model.NewId()}
m3 := &model.TeamMember{TeamId: teamId2, UserId: model.NewId()}
r1 := <-ss.Team().SaveMember(m1, -1)
require.Nil(t, r1.Err)
store.Must(ss.Team().SaveMember(m2, -1))
store.Must(ss.Team().SaveMember(m3, -1))
r1 = <-ss.Team().GetTeamsForUserWithPagination(m1.UserId, 0, 1)
require.Nil(t, r1.Err)
ms := r1.Data.([]*model.TeamMember)
require.Len(t, ms, 1)
require.Equal(t, m1.TeamId, ms[0].TeamId)
r1 = <-ss.Team().RemoveMember(teamId1, m1.UserId)
require.Nil(t, r1.Err)
r1 = <-ss.Team().GetMembers(teamId1, 0, 100)
require.Nil(t, r1.Err)
ms = r1.Data.([]*model.TeamMember)
require.Len(t, ms, 1)
require.Equal(t, m2.UserId, ms[0].UserId)
store.Must(ss.Team().SaveMember(m1, -1))
r1 = <-ss.Team().RemoveAllMembersByTeam(teamId1)
require.Nil(t, r1.Err)
uid := model.NewId()
m4 := &model.TeamMember{TeamId: teamId1, UserId: uid}
m5 := &model.TeamMember{TeamId: teamId2, UserId: uid}
store.Must(ss.Team().SaveMember(m4, -1))
store.Must(ss.Team().SaveMember(m5, -1))
r1 = <-ss.Team().GetTeamsForUserWithPagination(uid, 0, 1)
require.Nil(t, r1.Err)
ms = r1.Data.([]*model.TeamMember)
require.Len(t, ms, 1)
r1 = <-ss.Team().RemoveAllMembersByUser(uid)
require.Nil(t, r1.Err)
r1 = <-ss.Team().GetTeamsForUserWithPagination(uid, 1, 1)
require.Nil(t, r1.Err)
ms = r1.Data.([]*model.TeamMember)
require.Len(t, ms, 0)
}
func testSaveTeamMemberMaxMembers(t *testing.T, ss store.Store) {
maxUsersPerTeam := 5