feat: add count endpoint for users, enabling better pagination (#4848)

* Start on backend

* Hook up frontend

* Add to frontend test

* Add go test, wip

* Fix some test bugs

* Fix test

* Format

* Add to authorize.go

* copy user array into local variable

* Authorize route

* Log count error

* Authorize better

* Tweaks to authorization

* More authorization tweaks

* Make gen

* Fix test

Co-authored-by: Garrett <garrett@coder.com>
This commit is contained in:
Presley Pizzo
2022-11-08 10:58:44 -05:00
committed by GitHub
co-authored by Garrett
parent a4fbc74751
commit f496b149df
19 changed files with 620 additions and 216 deletions
@@ -457,6 +457,72 @@ func (q *fakeQuerier) GetActiveUserCount(_ context.Context) (int64, error) {
return active, nil
}
func (q *fakeQuerier) GetFilteredUserCount(ctx context.Context, arg database.GetFilteredUserCountParams) (int64, error) {
count, err := q.GetAuthorizedUserCount(ctx, arg, nil)
return count, err
}
func (q *fakeQuerier) GetAuthorizedUserCount(_ context.Context, params database.GetFilteredUserCountParams, authorizedFilter rbac.AuthorizeFilter) (int64, error) {
q.mutex.RLock()
defer q.mutex.RUnlock()
users := append([]database.User{}, q.users...)
if params.Deleted {
tmp := make([]database.User, 0, len(users))
for _, user := range users {
if user.Deleted {
tmp = append(tmp, user)
}
}
users = tmp
}
if params.Search != "" {
tmp := make([]database.User, 0, len(users))
for i, user := range users {
if strings.Contains(strings.ToLower(user.Email), strings.ToLower(params.Search)) {
tmp = append(tmp, users[i])
} else if strings.Contains(strings.ToLower(user.Username), strings.ToLower(params.Search)) {
tmp = append(tmp, users[i])
}
}
users = tmp
}
if len(params.Status) > 0 {
usersFilteredByStatus := make([]database.User, 0, len(users))
for i, user := range users {
if slice.ContainsCompare(params.Status, user.Status, func(a, b database.UserStatus) bool {
return strings.EqualFold(string(a), string(b))
}) {
usersFilteredByStatus = append(usersFilteredByStatus, users[i])
}
}
users = usersFilteredByStatus
}
if len(params.RbacRole) > 0 && !slice.Contains(params.RbacRole, rbac.RoleMember()) {
usersFilteredByRole := make([]database.User, 0, len(users))
for i, user := range users {
if slice.OverlapCompare(params.RbacRole, user.RBACRoles, strings.EqualFold) {
usersFilteredByRole = append(usersFilteredByRole, users[i])
}
}
users = usersFilteredByRole
}
for _, user := range q.workspaces {
// If the filter exists, ensure the object is authorized.
if authorizedFilter != nil && !authorizedFilter.Eval(user.RBACObject()) {
continue
}
}
return int64(len(users)), nil
}
func (q *fakeQuerier) UpdateUserDeletedByID(_ context.Context, params database.UpdateUserDeletedByIDParams) error {
q.mutex.Lock()
defer q.mutex.Unlock()