PLT-4481 Fix member count for team user lists and channel invite list (#4422)
* Fix member count for team user lists and channel invite list * Fix client unit test
Этот коммит содержится в:
коммит произвёл
Christopher Speller
родитель
263f290683
Коммит
00787974d0
23
api/team.go
23
api/team.go
@@ -902,16 +902,27 @@ func getTeamStats(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if result := <-Srv.Store.Team().GetMemberCount(c.TeamId); result.Err != nil {
|
tchan := Srv.Store.Team().GetTotalMemberCount(c.TeamId)
|
||||||
|
achan := Srv.Store.Team().GetActiveMemberCount(c.TeamId)
|
||||||
|
|
||||||
|
stats := &model.TeamStats{}
|
||||||
|
stats.TeamId = c.TeamId
|
||||||
|
|
||||||
|
if result := <-tchan; result.Err != nil {
|
||||||
c.Err = result.Err
|
c.Err = result.Err
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
stats := &model.TeamStats{}
|
stats.TotalMemberCount = result.Data.(int64)
|
||||||
stats.MemberCount = result.Data.(int64)
|
|
||||||
stats.TeamId = c.TeamId
|
|
||||||
w.Write([]byte(stats.ToJson()))
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if result := <-achan; result.Err != nil {
|
||||||
|
c.Err = result.Err
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
stats.ActiveMemberCount = result.Data.(int64)
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Write([]byte(stats.ToJson()))
|
||||||
}
|
}
|
||||||
|
|
||||||
func importTeam(c *Context, w http.ResponseWriter, r *http.Request) {
|
func importTeam(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
|||||||
@@ -706,7 +706,25 @@ func TestGetTeamStats(t *testing.T) {
|
|||||||
if result, err := th.SystemAdminClient.GetTeamStats(th.BasicTeam.Id); err != nil {
|
if result, err := th.SystemAdminClient.GetTeamStats(th.BasicTeam.Id); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
} else {
|
} else {
|
||||||
if result.Data.(*model.TeamStats).MemberCount != 2 {
|
if result.Data.(*model.TeamStats).TotalMemberCount != 2 {
|
||||||
|
t.Fatal("wrong count")
|
||||||
|
}
|
||||||
|
|
||||||
|
if result.Data.(*model.TeamStats).ActiveMemberCount != 2 {
|
||||||
|
t.Fatal("wrong count")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
th.SystemAdminClient.Must(th.SystemAdminClient.UpdateActive(th.BasicUser2.Id, false))
|
||||||
|
|
||||||
|
if result, err := th.SystemAdminClient.GetTeamStats(th.BasicTeam.Id); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else {
|
||||||
|
if result.Data.(*model.TeamStats).TotalMemberCount != 2 {
|
||||||
|
t.Fatal("wrong count")
|
||||||
|
}
|
||||||
|
|
||||||
|
if result.Data.(*model.TeamStats).ActiveMemberCount != 1 {
|
||||||
t.Fatal("wrong count")
|
t.Fatal("wrong count")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -714,7 +732,11 @@ func TestGetTeamStats(t *testing.T) {
|
|||||||
if result, err := th.SystemAdminClient.GetTeamStats("junk"); err != nil {
|
if result, err := th.SystemAdminClient.GetTeamStats("junk"); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
} else {
|
} else {
|
||||||
if result.Data.(*model.TeamStats).MemberCount != 0 {
|
if result.Data.(*model.TeamStats).TotalMemberCount != 0 {
|
||||||
|
t.Fatal("wrong count")
|
||||||
|
}
|
||||||
|
|
||||||
|
if result.Data.(*model.TeamStats).ActiveMemberCount != 0 {
|
||||||
t.Fatal("wrong count")
|
t.Fatal("wrong count")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -722,7 +744,7 @@ func TestGetTeamStats(t *testing.T) {
|
|||||||
if result, err := th.SystemAdminClient.GetTeamStats(th.BasicTeam.Id); err != nil {
|
if result, err := th.SystemAdminClient.GetTeamStats(th.BasicTeam.Id); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
} else {
|
} else {
|
||||||
if result.Data.(*model.TeamStats).MemberCount != 2 {
|
if result.Data.(*model.TeamStats).TotalMemberCount != 2 {
|
||||||
t.Fatal("wrong count")
|
t.Fatal("wrong count")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,8 @@ import (
|
|||||||
|
|
||||||
type TeamStats struct {
|
type TeamStats struct {
|
||||||
TeamId string `json:"team_id"`
|
TeamId string `json:"team_id"`
|
||||||
MemberCount int64 `json:"member_count"`
|
TotalMemberCount int64 `json:"total_member_count"`
|
||||||
|
ActiveMemberCount int64 `json:"active_member_count"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *TeamStats) ToJson() string {
|
func (o *TeamStats) ToJson() string {
|
||||||
|
|||||||
@@ -467,7 +467,36 @@ func (s SqlTeamStore) GetMembers(teamId string, offset int, limit int) StoreChan
|
|||||||
return storeChannel
|
return storeChannel
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s SqlTeamStore) GetMemberCount(teamId string) StoreChannel {
|
func (s SqlTeamStore) GetTotalMemberCount(teamId string) StoreChannel {
|
||||||
|
storeChannel := make(StoreChannel, 1)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
result := StoreResult{}
|
||||||
|
|
||||||
|
count, err := s.GetReplica().SelectInt(`
|
||||||
|
SELECT
|
||||||
|
count(*)
|
||||||
|
FROM
|
||||||
|
TeamMembers,
|
||||||
|
Users
|
||||||
|
WHERE
|
||||||
|
TeamMembers.UserId = Users.Id
|
||||||
|
AND TeamMembers.TeamId = :TeamId
|
||||||
|
AND TeamMembers.DeleteAt = 0`, map[string]interface{}{"TeamId": teamId})
|
||||||
|
if err != nil {
|
||||||
|
result.Err = model.NewLocAppError("SqlTeamStore.GetTotalMemberCount", "store.sql_team.get_member_count.app_error", nil, "teamId="+teamId+" "+err.Error())
|
||||||
|
} else {
|
||||||
|
result.Data = count
|
||||||
|
}
|
||||||
|
|
||||||
|
storeChannel <- result
|
||||||
|
close(storeChannel)
|
||||||
|
}()
|
||||||
|
|
||||||
|
return storeChannel
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s SqlTeamStore) GetActiveMemberCount(teamId string) StoreChannel {
|
||||||
storeChannel := make(StoreChannel, 1)
|
storeChannel := make(StoreChannel, 1)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
@@ -485,7 +514,7 @@ func (s SqlTeamStore) GetMemberCount(teamId string) StoreChannel {
|
|||||||
AND TeamMembers.DeleteAt = 0
|
AND TeamMembers.DeleteAt = 0
|
||||||
AND Users.DeleteAt = 0`, map[string]interface{}{"TeamId": teamId})
|
AND Users.DeleteAt = 0`, map[string]interface{}{"TeamId": teamId})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
result.Err = model.NewLocAppError("SqlTeamStore.GetMemberCount", "store.sql_team.get_member_count.app_error", nil, "teamId="+teamId+" "+err.Error())
|
result.Err = model.NewLocAppError("SqlTeamStore.GetActiveMemberCount", "store.sql_team.get_member_count.app_error", nil, "teamId="+teamId+" "+err.Error())
|
||||||
} else {
|
} else {
|
||||||
result.Data = count
|
result.Data = count
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -482,11 +482,27 @@ func TestTeamStoreMemberCount(t *testing.T) {
|
|||||||
u1.Email = model.NewId()
|
u1.Email = model.NewId()
|
||||||
Must(store.User().Save(u1))
|
Must(store.User().Save(u1))
|
||||||
|
|
||||||
|
u2 := &model.User{}
|
||||||
|
u2.Email = model.NewId()
|
||||||
|
u2.DeleteAt = 1
|
||||||
|
Must(store.User().Save(u2))
|
||||||
|
|
||||||
teamId1 := model.NewId()
|
teamId1 := model.NewId()
|
||||||
m1 := &model.TeamMember{TeamId: teamId1, UserId: u1.Id}
|
m1 := &model.TeamMember{TeamId: teamId1, UserId: u1.Id}
|
||||||
Must(store.Team().SaveMember(m1))
|
Must(store.Team().SaveMember(m1))
|
||||||
|
|
||||||
if result := <-store.Team().GetMemberCount(teamId1); result.Err != nil {
|
m2 := &model.TeamMember{TeamId: teamId1, UserId: u2.Id}
|
||||||
|
Must(store.Team().SaveMember(m2))
|
||||||
|
|
||||||
|
if result := <-store.Team().GetTotalMemberCount(teamId1); result.Err != nil {
|
||||||
|
t.Fatal(result.Err)
|
||||||
|
} else {
|
||||||
|
if result.Data.(int64) != 2 {
|
||||||
|
t.Fatal("wrong count")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if result := <-store.Team().GetActiveMemberCount(teamId1); result.Err != nil {
|
||||||
t.Fatal(result.Err)
|
t.Fatal(result.Err)
|
||||||
} else {
|
} else {
|
||||||
if result.Data.(int64) != 1 {
|
if result.Data.(int64) != 1 {
|
||||||
@@ -494,10 +510,18 @@ func TestTeamStoreMemberCount(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m2 := &model.TeamMember{TeamId: teamId1, UserId: model.NewId()}
|
m3 := &model.TeamMember{TeamId: teamId1, UserId: model.NewId()}
|
||||||
Must(store.Team().SaveMember(m2))
|
Must(store.Team().SaveMember(m3))
|
||||||
|
|
||||||
if result := <-store.Team().GetMemberCount(teamId1); result.Err != nil {
|
if result := <-store.Team().GetTotalMemberCount(teamId1); result.Err != nil {
|
||||||
|
t.Fatal(result.Err)
|
||||||
|
} else {
|
||||||
|
if result.Data.(int64) != 2 {
|
||||||
|
t.Fatal("wrong count")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if result := <-store.Team().GetActiveMemberCount(teamId1); result.Err != nil {
|
||||||
t.Fatal(result.Err)
|
t.Fatal(result.Err)
|
||||||
} else {
|
} else {
|
||||||
if result.Data.(int64) != 1 {
|
if result.Data.(int64) != 1 {
|
||||||
|
|||||||
@@ -70,7 +70,8 @@ type TeamStore interface {
|
|||||||
GetMember(teamId string, userId string) StoreChannel
|
GetMember(teamId string, userId string) StoreChannel
|
||||||
GetMembers(teamId string, offset int, limit int) StoreChannel
|
GetMembers(teamId string, offset int, limit int) StoreChannel
|
||||||
GetMembersByIds(teamId string, userIds []string) StoreChannel
|
GetMembersByIds(teamId string, userIds []string) StoreChannel
|
||||||
GetMemberCount(teamId string) StoreChannel
|
GetTotalMemberCount(teamId string) StoreChannel
|
||||||
|
GetActiveMemberCount(teamId string) StoreChannel
|
||||||
GetTeamsForUser(userId string) StoreChannel
|
GetTeamsForUser(userId string) StoreChannel
|
||||||
RemoveMember(teamId string, userId string) StoreChannel
|
RemoveMember(teamId string, userId string) StoreChannel
|
||||||
RemoveAllMembersByTeam(teamId string) StoreChannel
|
RemoveAllMembersByTeam(teamId string) StoreChannel
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ export default class UserList extends React.Component {
|
|||||||
team: AdminStore.getTeam(this.props.params.team),
|
team: AdminStore.getTeam(this.props.params.team),
|
||||||
users: [],
|
users: [],
|
||||||
teamMembers: TeamStore.getMembersInTeam(this.props.params.team),
|
teamMembers: TeamStore.getMembersInTeam(this.props.params.team),
|
||||||
total: stats.member_count,
|
total: stats.total_member_count,
|
||||||
serverError: null,
|
serverError: null,
|
||||||
showPasswordModal: false,
|
showPasswordModal: false,
|
||||||
loading: true,
|
loading: true,
|
||||||
@@ -75,7 +75,7 @@ export default class UserList extends React.Component {
|
|||||||
team: AdminStore.getTeam(nextProps.params.team),
|
team: AdminStore.getTeam(nextProps.params.team),
|
||||||
users: [],
|
users: [],
|
||||||
teamMembers: TeamStore.getMembersInTeam(nextProps.params.team),
|
teamMembers: TeamStore.getMembersInTeam(nextProps.params.team),
|
||||||
total: stats.member_count
|
total: stats.total_member_count
|
||||||
});
|
});
|
||||||
|
|
||||||
this.getTeamProfiles(nextProps.params.team);
|
this.getTeamProfiles(nextProps.params.team);
|
||||||
@@ -102,7 +102,7 @@ export default class UserList extends React.Component {
|
|||||||
|
|
||||||
onStatsChange() {
|
onStatsChange() {
|
||||||
const stats = TeamStore.getStats(this.props.params.team);
|
const stats = TeamStore.getStats(this.props.params.team);
|
||||||
this.setState({total: stats.member_count});
|
this.setState({total: stats.total_member_count});
|
||||||
}
|
}
|
||||||
|
|
||||||
onUsersChange() {
|
onUsersChange() {
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ export default class ChannelInviteModal extends React.Component {
|
|||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
users: null,
|
users: null,
|
||||||
total: teamStats.member_count - channelStats.member_count,
|
total: teamStats.active_member_count - channelStats.member_count,
|
||||||
show: true,
|
show: true,
|
||||||
search: false,
|
search: false,
|
||||||
statusChange: false
|
statusChange: false
|
||||||
@@ -72,8 +72,8 @@ export default class ChannelInviteModal extends React.Component {
|
|||||||
const teamStats = TeamStore.getCurrentStats();
|
const teamStats = TeamStore.getCurrentStats();
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
users: UserStore.getProfileListNotInChannel(this.props.channel.id),
|
users: UserStore.getProfileListNotInChannel(this.props.channel.id, true),
|
||||||
total: teamStats.member_count - channelStats.member_count
|
total: teamStats.active_member_count - channelStats.member_count
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ export default class MemberListTeam extends React.Component {
|
|||||||
this.state = {
|
this.state = {
|
||||||
users: UserStore.getProfileListInTeam(),
|
users: UserStore.getProfileListInTeam(),
|
||||||
teamMembers: Object.assign([], TeamStore.getMembersInTeam()),
|
teamMembers: Object.assign([], TeamStore.getMembersInTeam()),
|
||||||
total: stats.member_count,
|
total: stats.total_member_count,
|
||||||
search: false,
|
search: false,
|
||||||
loading: true
|
loading: true
|
||||||
};
|
};
|
||||||
@@ -67,7 +67,7 @@ export default class MemberListTeam extends React.Component {
|
|||||||
|
|
||||||
onStatsChange() {
|
onStatsChange() {
|
||||||
const stats = TeamStore.getCurrentStats();
|
const stats = TeamStore.getCurrentStats();
|
||||||
this.setState({total: stats.member_count});
|
this.setState({total: stats.total_member_count});
|
||||||
}
|
}
|
||||||
|
|
||||||
nextPage(page) {
|
nextPage(page) {
|
||||||
|
|||||||
@@ -320,6 +320,10 @@ class UserStoreClass extends EventEmitter {
|
|||||||
for (let i = 0; i < userIds.length; i++) {
|
for (let i = 0; i < userIds.length; i++) {
|
||||||
const profile = this.getProfile(userIds[i]);
|
const profile = this.getProfile(userIds[i]);
|
||||||
|
|
||||||
|
if (!profile) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (skipCurrent && profile.id === currentId) {
|
if (skipCurrent && profile.id === currentId) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -328,10 +332,8 @@ class UserStoreClass extends EventEmitter {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (profile) {
|
|
||||||
profiles.push(profile);
|
profiles.push(profile);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return profiles;
|
return profiles;
|
||||||
}
|
}
|
||||||
@@ -473,15 +475,22 @@ class UserStoreClass extends EventEmitter {
|
|||||||
userIds.splice(index, 1);
|
userIds.splice(index, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
getProfileListNotInChannel(channelId = ChannelStore.getCurrentId()) {
|
getProfileListNotInChannel(channelId = ChannelStore.getCurrentId(), skipInactive = false) {
|
||||||
const userIds = this.profiles_not_in_channel[channelId] || [];
|
const userIds = this.profiles_not_in_channel[channelId] || [];
|
||||||
const profiles = [];
|
const profiles = [];
|
||||||
|
|
||||||
for (let i = 0; i < userIds.length; i++) {
|
for (let i = 0; i < userIds.length; i++) {
|
||||||
const profile = this.getProfile(userIds[i]);
|
const profile = this.getProfile(userIds[i]);
|
||||||
if (profile) {
|
|
||||||
profiles.push(profile);
|
if (!profile) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (skipInactive && profile.delete_at > 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
profiles.push(profile);
|
||||||
}
|
}
|
||||||
|
|
||||||
return profiles;
|
return profiles;
|
||||||
|
|||||||
@@ -169,7 +169,7 @@ describe('Client.Team', function() {
|
|||||||
TestHelper.basicClient().getTeamStats(
|
TestHelper.basicClient().getTeamStats(
|
||||||
TestHelper.basicTeam().id,
|
TestHelper.basicTeam().id,
|
||||||
function(data) {
|
function(data) {
|
||||||
assert.equal(data.member_count > 0, true);
|
assert.equal(data.total_member_count > 0, true);
|
||||||
done();
|
done();
|
||||||
},
|
},
|
||||||
function(err) {
|
function(err) {
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user