[MM-26574] Add role filters to get users, users search and add getFilteredUserStats endpoint (#14998)
* MM-26574 Add role filters to user search and get * Add ability to get filtered user stats Add support for include bots * Add tests for user count with filters Add tests * Apply changes from code review * Fix guest filtering * Fix up tests related to guests * Clean role names * Trigger CI * Trigger CI
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
c53c9ed190
Коммит
c0bfa58ec1
@@ -458,6 +458,121 @@ func applyRoleFilter(query sq.SelectBuilder, role string, isPostgreSQL bool) sq.
|
||||
return query.Where("u.Roles LIKE ? ESCAPE '*'", roleParam)
|
||||
}
|
||||
|
||||
func applyMultiRoleFilters(query sq.SelectBuilder, roles []string, teamRoles []string, channelRoles []string) sq.SelectBuilder {
|
||||
queryString := ""
|
||||
if len(roles) > 0 && roles[0] != "" {
|
||||
schemeGuest := false
|
||||
schemeAdmin := false
|
||||
schemeUser := false
|
||||
|
||||
for _, role := range roles {
|
||||
switch role {
|
||||
case model.SYSTEM_ADMIN_ROLE_ID:
|
||||
schemeAdmin = true
|
||||
case model.SYSTEM_USER_ROLE_ID:
|
||||
schemeUser = true
|
||||
case model.SYSTEM_GUEST_ROLE_ID:
|
||||
schemeGuest = true
|
||||
}
|
||||
}
|
||||
|
||||
if schemeAdmin || schemeUser || schemeGuest {
|
||||
if schemeAdmin && schemeUser {
|
||||
queryString += `(u.Roles LIKE '%system_user%' OR u.Roles LIKE '%system_admin%') `
|
||||
} else if schemeAdmin {
|
||||
queryString += `(u.Roles LIKE '%system_admin%') `
|
||||
} else if schemeUser {
|
||||
queryString += `(u.Roles LIKE '%system_user%' AND u.Roles NOT LIKE '%system_admin%') `
|
||||
}
|
||||
|
||||
if schemeGuest {
|
||||
if queryString != "" {
|
||||
queryString += "OR "
|
||||
}
|
||||
queryString += `(u.Roles LIKE '%system_guest%') `
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(channelRoles) > 0 && channelRoles[0] != "" {
|
||||
schemeGuest := false
|
||||
schemeAdmin := false
|
||||
schemeUser := false
|
||||
for _, channelRole := range channelRoles {
|
||||
switch channelRole {
|
||||
case model.CHANNEL_ADMIN_ROLE_ID:
|
||||
schemeAdmin = true
|
||||
case model.CHANNEL_USER_ROLE_ID:
|
||||
schemeUser = true
|
||||
case model.CHANNEL_GUEST_ROLE_ID:
|
||||
schemeGuest = true
|
||||
}
|
||||
}
|
||||
|
||||
if schemeAdmin || schemeUser || schemeGuest {
|
||||
if queryString != "" {
|
||||
queryString += "OR "
|
||||
}
|
||||
if schemeAdmin && schemeUser {
|
||||
queryString += `(cm.SchemeUser = true AND u.Roles = 'system_user')`
|
||||
} else if schemeAdmin {
|
||||
queryString += `(cm.SchemeAdmin = true AND u.Roles = 'system_user')`
|
||||
} else if schemeUser {
|
||||
queryString += `(cm.SchemeUser = true AND cm.SchemeAdmin = false AND u.Roles = 'system_user')`
|
||||
}
|
||||
|
||||
if schemeGuest {
|
||||
if queryString != "" && queryString[len(queryString)-3:] != "OR " {
|
||||
queryString += "OR "
|
||||
}
|
||||
queryString += `(cm.SchemeGuest = true AND u.Roles = 'system_guest')`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(teamRoles) > 0 && teamRoles[0] != "" {
|
||||
schemeAdmin := false
|
||||
schemeUser := false
|
||||
schemeGuest := false
|
||||
for _, teamRole := range teamRoles {
|
||||
switch teamRole {
|
||||
case model.TEAM_ADMIN_ROLE_ID:
|
||||
schemeAdmin = true
|
||||
case model.TEAM_USER_ROLE_ID:
|
||||
schemeUser = true
|
||||
case model.TEAM_GUEST_ROLE_ID:
|
||||
schemeGuest = true
|
||||
}
|
||||
}
|
||||
|
||||
if schemeAdmin || schemeUser || schemeGuest {
|
||||
if queryString != "" {
|
||||
queryString += "OR "
|
||||
}
|
||||
if schemeAdmin && schemeUser {
|
||||
queryString += `(tm.SchemeUser = true AND u.Roles = 'system_user')`
|
||||
} else if schemeAdmin {
|
||||
queryString += `(tm.SchemeAdmin = true AND u.Roles = 'system_user')`
|
||||
} else if schemeUser {
|
||||
queryString += `(tm.SchemeUser = true AND tm.SchemeAdmin = false AND u.Roles = 'system_user')`
|
||||
}
|
||||
|
||||
if schemeGuest {
|
||||
if queryString != "" && queryString[len(queryString)-3:] != "OR " {
|
||||
queryString += "OR "
|
||||
}
|
||||
queryString += `(tm.SchemeGuest = true AND u.Roles = 'system_guest')`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if queryString != "" {
|
||||
query = query.Where("(" + queryString + ")")
|
||||
}
|
||||
|
||||
return query
|
||||
}
|
||||
|
||||
func applyChannelGroupConstrainedFilter(query sq.SelectBuilder, channelId string) sq.SelectBuilder {
|
||||
if channelId == "" {
|
||||
return query
|
||||
@@ -525,6 +640,7 @@ func (us SqlUserStore) GetProfiles(options *model.UserGetOptions) ([]*model.User
|
||||
query = applyViewRestrictionsFilter(query, options.ViewRestrictions, true)
|
||||
|
||||
query = applyRoleFilter(query, options.Role, isPostgreSQL)
|
||||
query = applyMultiRoleFilters(query, options.Roles, options.TeamRoles, options.ChannelRoles)
|
||||
|
||||
if options.Inactive {
|
||||
query = query.Where("u.DeleteAt != 0")
|
||||
@@ -1079,6 +1195,7 @@ func (us SqlUserStore) PermanentDelete(userId string) *model.AppError {
|
||||
}
|
||||
|
||||
func (us SqlUserStore) Count(options model.UserCountOptions) (int64, *model.AppError) {
|
||||
isPostgreSQL := us.DriverName() == model.DATABASE_DRIVER_POSTGRES
|
||||
query := us.getQueryBuilder().Select("COUNT(DISTINCT u.Id)").From("Users AS u")
|
||||
|
||||
if !options.IncludeDeleted {
|
||||
@@ -1099,10 +1216,13 @@ func (us SqlUserStore) Count(options model.UserCountOptions) (int64, *model.AppE
|
||||
|
||||
if options.TeamId != "" {
|
||||
query = query.LeftJoin("TeamMembers AS tm ON u.Id = tm.UserId").Where("tm.TeamId = ? AND tm.DeleteAt = 0", options.TeamId)
|
||||
} else if options.ChannelId != "" {
|
||||
query = query.LeftJoin("ChannelMembers AS cm ON u.Id = cm.UserId").Where("cm.ChannelId = ?", options.ChannelId)
|
||||
}
|
||||
query = applyViewRestrictionsFilter(query, options.ViewRestrictions, false)
|
||||
query = applyMultiRoleFilters(query, options.Roles, options.TeamRoles, options.ChannelRoles)
|
||||
|
||||
if us.DriverName() == model.DATABASE_DRIVER_POSTGRES {
|
||||
if isPostgreSQL {
|
||||
query = query.PlaceholderFormat(sq.Dollar)
|
||||
}
|
||||
|
||||
@@ -1309,6 +1429,7 @@ func (us SqlUserStore) performSearch(query sq.SelectBuilder, term string, option
|
||||
isPostgreSQL := us.DriverName() == model.DATABASE_DRIVER_POSTGRES
|
||||
|
||||
query = applyRoleFilter(query, options.Role, isPostgreSQL)
|
||||
query = applyMultiRoleFilters(query, options.Roles, options.TeamRoles, options.ChannelRoles)
|
||||
|
||||
if !options.AllowInactive {
|
||||
query = query.Where("u.DeleteAt = 0")
|
||||
|
||||
@@ -68,6 +68,7 @@ func TestUserStore(t *testing.T, ss store.Store, s SqlSupplier) {
|
||||
t.Run("UpdateMfaActive", func(t *testing.T) { testUserStoreUpdateMfaActive(t, ss) })
|
||||
t.Run("GetRecentlyActiveUsersForTeam", func(t *testing.T) { testUserStoreGetRecentlyActiveUsersForTeam(t, ss, s) })
|
||||
t.Run("GetNewUsersForTeam", func(t *testing.T) { testUserStoreGetNewUsersForTeam(t, ss) })
|
||||
t.Run("Search", func(t *testing.T) { testUserStoreSearch(t, ss) })
|
||||
t.Run("SearchNotInChannel", func(t *testing.T) { testUserStoreSearchNotInChannel(t, ss) })
|
||||
t.Run("SearchInChannel", func(t *testing.T) { testUserStoreSearchInChannel(t, ss) })
|
||||
t.Run("SearchNotInTeam", func(t *testing.T) { testUserStoreSearchNotInTeam(t, ss) })
|
||||
@@ -2291,6 +2292,153 @@ func assertUsers(t *testing.T, expected, actual []*model.User) {
|
||||
}
|
||||
}
|
||||
|
||||
func testUserStoreSearch(t *testing.T, ss store.Store) {
|
||||
u1 := &model.User{
|
||||
Username: "jimbo1" + model.NewId(),
|
||||
FirstName: "Tim",
|
||||
LastName: "Bill",
|
||||
Nickname: "Rob",
|
||||
Email: "harold" + model.NewId() + "@simulator.amazonses.com",
|
||||
Roles: "system_user system_admin",
|
||||
}
|
||||
_, err := ss.User().Save(u1)
|
||||
require.Nil(t, err)
|
||||
defer func() { require.Nil(t, ss.User().PermanentDelete(u1.Id)) }()
|
||||
|
||||
u2 := &model.User{
|
||||
Username: "jim2-bobby" + model.NewId(),
|
||||
Email: MakeEmail(),
|
||||
Roles: "system_user",
|
||||
}
|
||||
_, err = ss.User().Save(u2)
|
||||
require.Nil(t, err)
|
||||
defer func() { require.Nil(t, ss.User().PermanentDelete(u2.Id)) }()
|
||||
|
||||
u3 := &model.User{
|
||||
Username: "jimbo3" + model.NewId(),
|
||||
Email: MakeEmail(),
|
||||
Roles: "system_guest",
|
||||
}
|
||||
_, err = ss.User().Save(u3)
|
||||
require.Nil(t, err)
|
||||
defer func() { require.Nil(t, ss.User().PermanentDelete(u3.Id)) }()
|
||||
|
||||
// The users returned from the database will have AuthData as an empty string.
|
||||
nilAuthData := new(string)
|
||||
*nilAuthData = ""
|
||||
u1.AuthData = nilAuthData
|
||||
u2.AuthData = nilAuthData
|
||||
u3.AuthData = nilAuthData
|
||||
|
||||
t1id := model.NewId()
|
||||
_, err = ss.Team().SaveMember(&model.TeamMember{TeamId: t1id, UserId: u1.Id, SchemeAdmin: true, SchemeUser: true}, -1)
|
||||
require.Nil(t, err)
|
||||
_, err = ss.Team().SaveMember(&model.TeamMember{TeamId: t1id, UserId: u2.Id, SchemeAdmin: true, SchemeUser: true}, -1)
|
||||
require.Nil(t, err)
|
||||
_, err = ss.Team().SaveMember(&model.TeamMember{TeamId: t1id, UserId: u3.Id, SchemeAdmin: false, SchemeUser: false, SchemeGuest: true}, -1)
|
||||
require.Nil(t, err)
|
||||
|
||||
testCases := []struct {
|
||||
Description string
|
||||
TeamId string
|
||||
Term string
|
||||
Options *model.UserSearchOptions
|
||||
Expected []*model.User
|
||||
}{
|
||||
{
|
||||
"search jimb, team 1",
|
||||
t1id,
|
||||
"jimb",
|
||||
&model.UserSearchOptions{
|
||||
AllowFullNames: true,
|
||||
Limit: model.USER_SEARCH_DEFAULT_LIMIT,
|
||||
},
|
||||
[]*model.User{u1, u3},
|
||||
},
|
||||
{
|
||||
"search jimb, team 1 with team guest and team admin filters without sys admin filter",
|
||||
t1id,
|
||||
"jimb",
|
||||
&model.UserSearchOptions{
|
||||
AllowFullNames: true,
|
||||
Limit: model.USER_SEARCH_DEFAULT_LIMIT,
|
||||
TeamRoles: []string{model.TEAM_GUEST_ROLE_ID, model.TEAM_ADMIN_ROLE_ID},
|
||||
},
|
||||
[]*model.User{u3},
|
||||
},
|
||||
{
|
||||
"search jimb, team 1 with team admin filter and sys admin filter",
|
||||
t1id,
|
||||
"jimb",
|
||||
&model.UserSearchOptions{
|
||||
AllowFullNames: true,
|
||||
Limit: model.USER_SEARCH_DEFAULT_LIMIT,
|
||||
Roles: []string{model.SYSTEM_ADMIN_ROLE_ID},
|
||||
TeamRoles: []string{model.TEAM_ADMIN_ROLE_ID},
|
||||
},
|
||||
[]*model.User{u1},
|
||||
},
|
||||
{
|
||||
"search jim, team 1 with team admin filter",
|
||||
t1id,
|
||||
"jim",
|
||||
&model.UserSearchOptions{
|
||||
AllowFullNames: true,
|
||||
Limit: model.USER_SEARCH_DEFAULT_LIMIT,
|
||||
TeamRoles: []string{model.TEAM_ADMIN_ROLE_ID},
|
||||
},
|
||||
[]*model.User{u2},
|
||||
},
|
||||
{
|
||||
"search jim, team 1 with team admin and team guest filter",
|
||||
t1id,
|
||||
"jim",
|
||||
&model.UserSearchOptions{
|
||||
AllowFullNames: true,
|
||||
Limit: model.USER_SEARCH_DEFAULT_LIMIT,
|
||||
TeamRoles: []string{model.TEAM_ADMIN_ROLE_ID, model.TEAM_GUEST_ROLE_ID},
|
||||
},
|
||||
[]*model.User{u2, u3},
|
||||
},
|
||||
{
|
||||
"search jim, team 1 with team admin and system admin filters",
|
||||
t1id,
|
||||
"jim",
|
||||
&model.UserSearchOptions{
|
||||
AllowFullNames: true,
|
||||
Limit: model.USER_SEARCH_DEFAULT_LIMIT,
|
||||
Roles: []string{model.SYSTEM_ADMIN_ROLE_ID},
|
||||
TeamRoles: []string{model.TEAM_ADMIN_ROLE_ID},
|
||||
},
|
||||
[]*model.User{u2, u1},
|
||||
},
|
||||
{
|
||||
"search jim, team 1 with system guest filter",
|
||||
t1id,
|
||||
"jim",
|
||||
&model.UserSearchOptions{
|
||||
AllowFullNames: true,
|
||||
Limit: model.USER_SEARCH_DEFAULT_LIMIT,
|
||||
Roles: []string{model.SYSTEM_GUEST_ROLE_ID},
|
||||
TeamRoles: []string{},
|
||||
},
|
||||
[]*model.User{u3},
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.Description, func(t *testing.T) {
|
||||
users, err := ss.User().Search(
|
||||
testCase.TeamId,
|
||||
testCase.Term,
|
||||
testCase.Options,
|
||||
)
|
||||
require.Nil(t, err)
|
||||
assertUsers(t, testCase.Expected, users)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func testUserStoreSearchNotInChannel(t *testing.T, ss store.Store) {
|
||||
u1 := &model.User{
|
||||
Username: "jimbo1" + model.NewId(),
|
||||
@@ -2524,6 +2672,7 @@ func testUserStoreSearchInChannel(t *testing.T, ss store.Store) {
|
||||
LastName: "Bill",
|
||||
Nickname: "Rob",
|
||||
Email: "harold" + model.NewId() + "@simulator.amazonses.com",
|
||||
Roles: "system_user system_admin",
|
||||
}
|
||||
_, err := ss.User().Save(u1)
|
||||
require.Nil(t, err)
|
||||
@@ -2532,6 +2681,7 @@ func testUserStoreSearchInChannel(t *testing.T, ss store.Store) {
|
||||
u2 := &model.User{
|
||||
Username: "jim-bobby" + model.NewId(),
|
||||
Email: MakeEmail(),
|
||||
Roles: "system_user",
|
||||
}
|
||||
_, err = ss.User().Save(u2)
|
||||
require.Nil(t, err)
|
||||
@@ -2541,6 +2691,7 @@ func testUserStoreSearchInChannel(t *testing.T, ss store.Store) {
|
||||
Username: "jimbo3" + model.NewId(),
|
||||
Email: MakeEmail(),
|
||||
DeleteAt: 1,
|
||||
Roles: "system_user",
|
||||
}
|
||||
_, err = ss.User().Save(u3)
|
||||
require.Nil(t, err)
|
||||
@@ -2592,18 +2743,24 @@ func testUserStoreSearchInChannel(t *testing.T, ss store.Store) {
|
||||
ChannelId: c1.Id,
|
||||
UserId: u1.Id,
|
||||
NotifyProps: model.GetDefaultChannelNotifyProps(),
|
||||
SchemeAdmin: true,
|
||||
SchemeUser: true,
|
||||
})
|
||||
require.Nil(t, err)
|
||||
_, err = ss.Channel().SaveMember(&model.ChannelMember{
|
||||
ChannelId: c2.Id,
|
||||
UserId: u2.Id,
|
||||
NotifyProps: model.GetDefaultChannelNotifyProps(),
|
||||
SchemeAdmin: false,
|
||||
SchemeUser: true,
|
||||
})
|
||||
require.Nil(t, err)
|
||||
_, err = ss.Channel().SaveMember(&model.ChannelMember{
|
||||
ChannelId: c1.Id,
|
||||
UserId: u3.Id,
|
||||
NotifyProps: model.GetDefaultChannelNotifyProps(),
|
||||
SchemeAdmin: false,
|
||||
SchemeUser: true,
|
||||
})
|
||||
require.Nil(t, err)
|
||||
|
||||
@@ -2667,6 +2824,66 @@ func testUserStoreSearchInChannel(t *testing.T, ss store.Store) {
|
||||
},
|
||||
[]*model.User{},
|
||||
},
|
||||
{
|
||||
"search jim, allow inactive, channel 1 with system admin filter",
|
||||
c1.Id,
|
||||
"jim",
|
||||
&model.UserSearchOptions{
|
||||
AllowFullNames: true,
|
||||
AllowInactive: true,
|
||||
Limit: model.USER_SEARCH_DEFAULT_LIMIT,
|
||||
Roles: []string{model.SYSTEM_ADMIN_ROLE_ID},
|
||||
},
|
||||
[]*model.User{u1},
|
||||
},
|
||||
{
|
||||
"search jim, allow inactive, channel 1 with system admin and system user filter",
|
||||
c1.Id,
|
||||
"jim",
|
||||
&model.UserSearchOptions{
|
||||
AllowFullNames: true,
|
||||
AllowInactive: true,
|
||||
Limit: model.USER_SEARCH_DEFAULT_LIMIT,
|
||||
Roles: []string{model.SYSTEM_ADMIN_ROLE_ID, model.SYSTEM_USER_ROLE_ID},
|
||||
},
|
||||
[]*model.User{u1, u3},
|
||||
},
|
||||
{
|
||||
"search jim, allow inactive, channel 1 with channel user filter",
|
||||
c1.Id,
|
||||
"jim",
|
||||
&model.UserSearchOptions{
|
||||
AllowFullNames: true,
|
||||
AllowInactive: true,
|
||||
Limit: model.USER_SEARCH_DEFAULT_LIMIT,
|
||||
ChannelRoles: []string{model.CHANNEL_USER_ROLE_ID},
|
||||
},
|
||||
[]*model.User{u3},
|
||||
},
|
||||
{
|
||||
"search jim, allow inactive, channel 1 with channel user and channel admin filter",
|
||||
c1.Id,
|
||||
"jim",
|
||||
&model.UserSearchOptions{
|
||||
AllowFullNames: true,
|
||||
AllowInactive: true,
|
||||
Limit: model.USER_SEARCH_DEFAULT_LIMIT,
|
||||
ChannelRoles: []string{model.CHANNEL_USER_ROLE_ID, model.CHANNEL_ADMIN_ROLE_ID},
|
||||
},
|
||||
[]*model.User{u3},
|
||||
},
|
||||
{
|
||||
"search jim, allow inactive, channel 2 with channel user filter",
|
||||
c2.Id,
|
||||
"jim",
|
||||
&model.UserSearchOptions{
|
||||
AllowFullNames: true,
|
||||
AllowInactive: true,
|
||||
Limit: model.USER_SEARCH_DEFAULT_LIMIT,
|
||||
ChannelRoles: []string{model.CHANNEL_USER_ROLE_ID},
|
||||
},
|
||||
[]*model.User{u2},
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
@@ -3122,111 +3339,287 @@ func testUserStoreSearchInGroup(t *testing.T, ss store.Store) {
|
||||
func testCount(t *testing.T, ss store.Store) {
|
||||
// Regular
|
||||
teamId := model.NewId()
|
||||
u1 := &model.User{}
|
||||
u1.Email = MakeEmail()
|
||||
_, err := ss.User().Save(u1)
|
||||
channelId := model.NewId()
|
||||
regularUser := &model.User{}
|
||||
regularUser.Email = MakeEmail()
|
||||
regularUser.Roles = model.SYSTEM_USER_ROLE_ID
|
||||
_, err := ss.User().Save(regularUser)
|
||||
require.Nil(t, err)
|
||||
defer func() { require.Nil(t, ss.User().PermanentDelete(u1.Id)) }()
|
||||
_, err = ss.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u1.Id}, -1)
|
||||
defer func() { require.Nil(t, ss.User().PermanentDelete(regularUser.Id)) }()
|
||||
_, err = ss.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: regularUser.Id, SchemeAdmin: false, SchemeUser: true}, -1)
|
||||
require.Nil(t, err)
|
||||
_, err = ss.Channel().SaveMember(&model.ChannelMember{UserId: regularUser.Id, ChannelId: channelId, SchemeAdmin: false, SchemeUser: true, NotifyProps: model.GetDefaultChannelNotifyProps()})
|
||||
require.Nil(t, err)
|
||||
|
||||
guestUser := &model.User{}
|
||||
guestUser.Email = MakeEmail()
|
||||
guestUser.Roles = model.SYSTEM_GUEST_ROLE_ID
|
||||
_, err = ss.User().Save(guestUser)
|
||||
require.Nil(t, err)
|
||||
defer func() { require.Nil(t, ss.User().PermanentDelete(guestUser.Id)) }()
|
||||
_, err = ss.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: guestUser.Id, SchemeAdmin: false, SchemeUser: false, SchemeGuest: true}, -1)
|
||||
require.Nil(t, err)
|
||||
_, err = ss.Channel().SaveMember(&model.ChannelMember{UserId: guestUser.Id, ChannelId: channelId, SchemeAdmin: false, SchemeUser: false, SchemeGuest: true, NotifyProps: model.GetDefaultChannelNotifyProps()})
|
||||
require.Nil(t, err)
|
||||
|
||||
teamAdmin := &model.User{}
|
||||
teamAdmin.Email = MakeEmail()
|
||||
teamAdmin.Roles = model.SYSTEM_USER_ROLE_ID
|
||||
_, err = ss.User().Save(teamAdmin)
|
||||
require.Nil(t, err)
|
||||
defer func() { require.Nil(t, ss.User().PermanentDelete(teamAdmin.Id)) }()
|
||||
_, err = ss.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: teamAdmin.Id, SchemeAdmin: true, SchemeUser: true}, -1)
|
||||
require.Nil(t, err)
|
||||
_, err = ss.Channel().SaveMember(&model.ChannelMember{UserId: teamAdmin.Id, ChannelId: channelId, SchemeAdmin: true, SchemeUser: true, NotifyProps: model.GetDefaultChannelNotifyProps()})
|
||||
require.Nil(t, err)
|
||||
|
||||
sysAdmin := &model.User{}
|
||||
sysAdmin.Email = MakeEmail()
|
||||
sysAdmin.Roles = model.SYSTEM_ADMIN_ROLE_ID + " " + model.SYSTEM_USER_ROLE_ID
|
||||
_, err = ss.User().Save(sysAdmin)
|
||||
require.Nil(t, err)
|
||||
defer func() { require.Nil(t, ss.User().PermanentDelete(sysAdmin.Id)) }()
|
||||
_, err = ss.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: sysAdmin.Id, SchemeAdmin: false, SchemeUser: true}, -1)
|
||||
require.Nil(t, err)
|
||||
_, err = ss.Channel().SaveMember(&model.ChannelMember{UserId: sysAdmin.Id, ChannelId: channelId, SchemeAdmin: true, SchemeUser: true, NotifyProps: model.GetDefaultChannelNotifyProps()})
|
||||
require.Nil(t, err)
|
||||
|
||||
// Deleted
|
||||
u2 := &model.User{}
|
||||
u2.Email = MakeEmail()
|
||||
u2.DeleteAt = model.GetMillis()
|
||||
_, err = ss.User().Save(u2)
|
||||
deletedUser := &model.User{}
|
||||
deletedUser.Email = MakeEmail()
|
||||
deletedUser.DeleteAt = model.GetMillis()
|
||||
_, err = ss.User().Save(deletedUser)
|
||||
require.Nil(t, err)
|
||||
defer func() { require.Nil(t, ss.User().PermanentDelete(u2.Id)) }()
|
||||
defer func() { require.Nil(t, ss.User().PermanentDelete(deletedUser.Id)) }()
|
||||
|
||||
// Bot
|
||||
u3, err := ss.User().Save(&model.User{
|
||||
botUser, err := ss.User().Save(&model.User{
|
||||
Email: MakeEmail(),
|
||||
})
|
||||
require.Nil(t, err)
|
||||
defer func() { require.Nil(t, ss.User().PermanentDelete(u3.Id)) }()
|
||||
defer func() { require.Nil(t, ss.User().PermanentDelete(botUser.Id)) }()
|
||||
_, nErr := ss.Bot().Save(&model.Bot{
|
||||
UserId: u3.Id,
|
||||
Username: u3.Username,
|
||||
OwnerId: u1.Id,
|
||||
UserId: botUser.Id,
|
||||
Username: botUser.Username,
|
||||
OwnerId: regularUser.Id,
|
||||
})
|
||||
require.Nil(t, nErr)
|
||||
u3.IsBot = true
|
||||
defer func() { require.Nil(t, ss.Bot().PermanentDelete(u3.Id)) }()
|
||||
botUser.IsBot = true
|
||||
defer func() { require.Nil(t, ss.Bot().PermanentDelete(botUser.Id)) }()
|
||||
|
||||
count, err := ss.User().Count(model.UserCountOptions{
|
||||
IncludeBotAccounts: false,
|
||||
IncludeDeleted: false,
|
||||
TeamId: "",
|
||||
})
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, int64(1), count)
|
||||
|
||||
count, err = ss.User().Count(model.UserCountOptions{
|
||||
IncludeBotAccounts: true,
|
||||
IncludeDeleted: false,
|
||||
TeamId: "",
|
||||
})
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, int64(2), count)
|
||||
|
||||
count, err = ss.User().Count(model.UserCountOptions{
|
||||
IncludeBotAccounts: false,
|
||||
IncludeDeleted: true,
|
||||
TeamId: "",
|
||||
})
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, int64(2), count)
|
||||
|
||||
count, err = ss.User().Count(model.UserCountOptions{
|
||||
IncludeBotAccounts: true,
|
||||
IncludeDeleted: true,
|
||||
TeamId: "",
|
||||
})
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, int64(3), count)
|
||||
|
||||
count, err = ss.User().Count(model.UserCountOptions{
|
||||
IncludeBotAccounts: true,
|
||||
IncludeDeleted: true,
|
||||
ExcludeRegularUsers: true,
|
||||
TeamId: "",
|
||||
})
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, int64(1), count)
|
||||
|
||||
count, err = ss.User().Count(model.UserCountOptions{
|
||||
IncludeBotAccounts: true,
|
||||
IncludeDeleted: true,
|
||||
TeamId: teamId,
|
||||
})
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, int64(1), count)
|
||||
|
||||
count, err = ss.User().Count(model.UserCountOptions{
|
||||
IncludeBotAccounts: true,
|
||||
IncludeDeleted: true,
|
||||
TeamId: model.NewId(),
|
||||
})
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, int64(0), count)
|
||||
|
||||
count, err = ss.User().Count(model.UserCountOptions{
|
||||
IncludeBotAccounts: true,
|
||||
IncludeDeleted: true,
|
||||
TeamId: teamId,
|
||||
ViewRestrictions: &model.ViewUsersRestrictions{Teams: []string{teamId}},
|
||||
})
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, int64(1), count)
|
||||
|
||||
count, err = ss.User().Count(model.UserCountOptions{
|
||||
IncludeBotAccounts: true,
|
||||
IncludeDeleted: true,
|
||||
TeamId: teamId,
|
||||
ViewRestrictions: &model.ViewUsersRestrictions{Teams: []string{model.NewId()}},
|
||||
})
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, int64(0), count)
|
||||
testCases := []struct {
|
||||
Description string
|
||||
Options model.UserCountOptions
|
||||
Expected int64
|
||||
}{
|
||||
{
|
||||
"No bot accounts no deleted accounts and no team id",
|
||||
model.UserCountOptions{
|
||||
IncludeBotAccounts: false,
|
||||
IncludeDeleted: false,
|
||||
TeamId: "",
|
||||
},
|
||||
4,
|
||||
},
|
||||
{
|
||||
"Include bot accounts no deleted accounts and no team id",
|
||||
model.UserCountOptions{
|
||||
IncludeBotAccounts: true,
|
||||
IncludeDeleted: false,
|
||||
TeamId: "",
|
||||
},
|
||||
5,
|
||||
},
|
||||
{
|
||||
"Include delete accounts no bots and no team id",
|
||||
model.UserCountOptions{
|
||||
IncludeBotAccounts: false,
|
||||
IncludeDeleted: true,
|
||||
TeamId: "",
|
||||
},
|
||||
5,
|
||||
},
|
||||
{
|
||||
"Include bot accounts and deleted accounts and no team id",
|
||||
model.UserCountOptions{
|
||||
IncludeBotAccounts: true,
|
||||
IncludeDeleted: true,
|
||||
TeamId: "",
|
||||
},
|
||||
6,
|
||||
},
|
||||
{
|
||||
"Include bot accounts, deleted accounts, exclude regular users with no team id",
|
||||
model.UserCountOptions{
|
||||
IncludeBotAccounts: true,
|
||||
IncludeDeleted: true,
|
||||
ExcludeRegularUsers: true,
|
||||
TeamId: "",
|
||||
},
|
||||
1,
|
||||
},
|
||||
{
|
||||
"Include bot accounts and deleted accounts with existing team id",
|
||||
model.UserCountOptions{
|
||||
IncludeBotAccounts: true,
|
||||
IncludeDeleted: true,
|
||||
TeamId: teamId,
|
||||
},
|
||||
4,
|
||||
},
|
||||
{
|
||||
"Include bot accounts and deleted accounts with fake team id",
|
||||
model.UserCountOptions{
|
||||
IncludeBotAccounts: true,
|
||||
IncludeDeleted: true,
|
||||
TeamId: model.NewId(),
|
||||
},
|
||||
0,
|
||||
},
|
||||
{
|
||||
"Include bot accounts and deleted accounts with existing team id and view restrictions allowing team",
|
||||
model.UserCountOptions{
|
||||
IncludeBotAccounts: true,
|
||||
IncludeDeleted: true,
|
||||
TeamId: teamId,
|
||||
ViewRestrictions: &model.ViewUsersRestrictions{Teams: []string{teamId}},
|
||||
},
|
||||
4,
|
||||
},
|
||||
{
|
||||
"Include bot accounts and deleted accounts with existing team id and view restrictions not allowing current team",
|
||||
model.UserCountOptions{
|
||||
IncludeBotAccounts: true,
|
||||
IncludeDeleted: true,
|
||||
TeamId: teamId,
|
||||
ViewRestrictions: &model.ViewUsersRestrictions{Teams: []string{model.NewId()}},
|
||||
},
|
||||
0,
|
||||
},
|
||||
{
|
||||
"Filter by system admins only",
|
||||
model.UserCountOptions{
|
||||
TeamId: teamId,
|
||||
Roles: []string{model.SYSTEM_ADMIN_ROLE_ID},
|
||||
},
|
||||
1,
|
||||
},
|
||||
{
|
||||
"Filter by system users only",
|
||||
model.UserCountOptions{
|
||||
TeamId: teamId,
|
||||
Roles: []string{model.SYSTEM_USER_ROLE_ID},
|
||||
},
|
||||
2,
|
||||
},
|
||||
{
|
||||
"Filter by system guests only",
|
||||
model.UserCountOptions{
|
||||
TeamId: teamId,
|
||||
Roles: []string{model.SYSTEM_GUEST_ROLE_ID},
|
||||
},
|
||||
1,
|
||||
},
|
||||
{
|
||||
"Filter by system admins and system users",
|
||||
model.UserCountOptions{
|
||||
TeamId: teamId,
|
||||
Roles: []string{model.SYSTEM_ADMIN_ROLE_ID, model.SYSTEM_USER_ROLE_ID},
|
||||
},
|
||||
3,
|
||||
},
|
||||
{
|
||||
"Filter by system admins, system user and system guests",
|
||||
model.UserCountOptions{
|
||||
TeamId: teamId,
|
||||
Roles: []string{model.SYSTEM_ADMIN_ROLE_ID, model.SYSTEM_USER_ROLE_ID, model.SYSTEM_GUEST_ROLE_ID},
|
||||
},
|
||||
4,
|
||||
},
|
||||
{
|
||||
"Filter by team admins",
|
||||
model.UserCountOptions{
|
||||
TeamId: teamId,
|
||||
TeamRoles: []string{model.TEAM_ADMIN_ROLE_ID},
|
||||
},
|
||||
1,
|
||||
},
|
||||
{
|
||||
"Filter by team members",
|
||||
model.UserCountOptions{
|
||||
TeamId: teamId,
|
||||
TeamRoles: []string{model.TEAM_USER_ROLE_ID},
|
||||
},
|
||||
1,
|
||||
},
|
||||
{
|
||||
"Filter by team guests",
|
||||
model.UserCountOptions{
|
||||
TeamId: teamId,
|
||||
TeamRoles: []string{model.TEAM_GUEST_ROLE_ID},
|
||||
},
|
||||
1,
|
||||
},
|
||||
{
|
||||
"Filter by team guests and any system role",
|
||||
model.UserCountOptions{
|
||||
TeamId: teamId,
|
||||
TeamRoles: []string{model.TEAM_GUEST_ROLE_ID},
|
||||
Roles: []string{model.SYSTEM_ADMIN_ROLE_ID},
|
||||
},
|
||||
2,
|
||||
},
|
||||
{
|
||||
"Filter by channel members",
|
||||
model.UserCountOptions{
|
||||
ChannelId: channelId,
|
||||
ChannelRoles: []string{model.CHANNEL_USER_ROLE_ID},
|
||||
},
|
||||
1,
|
||||
},
|
||||
{
|
||||
"Filter by channel members and system admins",
|
||||
model.UserCountOptions{
|
||||
ChannelId: channelId,
|
||||
Roles: []string{model.SYSTEM_ADMIN_ROLE_ID},
|
||||
ChannelRoles: []string{model.CHANNEL_USER_ROLE_ID},
|
||||
},
|
||||
2,
|
||||
},
|
||||
{
|
||||
"Filter by channel members and system admins and channel admins",
|
||||
model.UserCountOptions{
|
||||
ChannelId: channelId,
|
||||
Roles: []string{model.SYSTEM_ADMIN_ROLE_ID},
|
||||
ChannelRoles: []string{model.CHANNEL_USER_ROLE_ID, model.CHANNEL_ADMIN_ROLE_ID},
|
||||
},
|
||||
3,
|
||||
},
|
||||
{
|
||||
"Filter by channel guests",
|
||||
model.UserCountOptions{
|
||||
ChannelId: channelId,
|
||||
ChannelRoles: []string{model.CHANNEL_GUEST_ROLE_ID},
|
||||
},
|
||||
1,
|
||||
},
|
||||
{
|
||||
"Filter by channel guests and any system role",
|
||||
model.UserCountOptions{
|
||||
ChannelId: channelId,
|
||||
ChannelRoles: []string{model.CHANNEL_GUEST_ROLE_ID},
|
||||
Roles: []string{model.SYSTEM_ADMIN_ROLE_ID},
|
||||
},
|
||||
2,
|
||||
},
|
||||
}
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.Description, func(t *testing.T) {
|
||||
count, err := ss.User().Count(testCase.Options)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, testCase.Expected, count)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func testUserStoreAnalyticsActiveCount(t *testing.T, ss store.Store, s SqlSupplier) {
|
||||
|
||||
Ссылка в новой задаче
Block a user