Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show active and pending users separately (for admins) #3400

Merged
merged 12 commits into from
Feb 7, 2019
27 changes: 25 additions & 2 deletions client/app/pages/users/UsersList.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ class UsersList extends React.Component {
href: 'users',
title: 'Active Users',
},
{
key: 'pending',
href: 'users/pending',
title: 'Invited Users',
},
{
key: 'disabled',
href: 'users/disabled',
Expand Down Expand Up @@ -218,8 +223,21 @@ export default function init(ngModule) {
ngModule.component('pageUsersList', react2angular(liveItemsList(UsersList, {
defaultOrderBy: '-created_at',
getRequest(request, { currentPage }) {
if (currentPage === 'disabled') {
request.disabled = true;
switch (currentPage) {
case 'active':
// Admin can see sidebar menu, so load active and pending users separately;
// for non-admins load both together
if (policy.canCreateUser()) {
request.pending = false;
}
break;
case 'pending':
request.pending = true;
break;
case 'disabled':
request.disabled = true;
break;
// no default
}
return request;
},
Expand Down Expand Up @@ -256,6 +274,11 @@ export default function init(ngModule) {
title: 'Users',
key: 'active',
},
{
path: '/users/pending',
title: 'Invited Users',
kravets-levko marked this conversation as resolved.
Show resolved Hide resolved
key: 'pending',
},
{
path: '/users/disabled',
title: 'Disabled Users',
Expand Down
14 changes: 13 additions & 1 deletion redash/handlers/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,18 @@ def invite_user(org, inviter, user):
send_invite_email(inviter, user, invite_url, org)


def bool_or_none(v):
kravets-levko marked this conversation as resolved.
Show resolved Hide resolved
if v in (None, True, False):
return v
v = v.strip().lower()
if v in ('yes', 'true', 'on', '1'):
return True
elif v in ('no', 'false', 'off', '0', 'none'):
return False
else:
return None


class UserListResource(BaseResource):
@require_permission('list_users')
def get(self):
Expand All @@ -66,7 +78,7 @@ def serialize_user(user):
if request.args.get('disabled', None) is not None:
users = models.User.all_disabled(self.current_org)
else:
users = models.User.all(self.current_org)
users = models.User.all(self.current_org, bool_or_none(request.args.get('pending', None)))

if search_term:
users = models.User.search(users, search_term)
Expand Down
10 changes: 8 additions & 2 deletions redash/models/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,8 +187,14 @@ def get_by_api_key_and_org(cls, api_key, org):
return cls.get_by_org(org).filter(cls.api_key == api_key).one()

@classmethod
def all(cls, org):
return cls.get_by_org(org).filter(cls.disabled_at.is_(None))
def all(cls, org, is_invitation_pending=None):
kravets-levko marked this conversation as resolved.
Show resolved Hide resolved
condition = True # no filter
if is_invitation_pending is not None:
if is_invitation_pending:
condition = cls.is_invitation_pending.is_(True) # pending
else:
condition = cls.is_invitation_pending.isnot(True) # not pending (check for both `false`/`null`)
return cls.get_by_org(org).filter(cls.disabled_at.is_(None), condition)
kravets-levko marked this conversation as resolved.
Show resolved Hide resolved

@classmethod
def search(cls, base_query, term):
Expand Down