Optimize lookup of org membership on prototype and perms APIs
Fixes a major slowdown when working with permissions under organizations with a lot of members Fixes https://www.pivotaltracker.com/story/show/144076113
This commit is contained in:
parent
f5e4380a57
commit
db767b3610
3 changed files with 37 additions and 17 deletions
|
@ -106,15 +106,28 @@ def remove_organization_member(org, user_obj):
|
||||||
TeamMember.delete().where(TeamMember.id << members).execute()
|
TeamMember.delete().where(TeamMember.id << members).execute()
|
||||||
|
|
||||||
|
|
||||||
def get_organization_member_set(orgname):
|
def get_organization_member_set(org, include_robots=False, users_filter=None):
|
||||||
|
""" Returns the set of all member usernames under the given organization, with optional
|
||||||
|
filtering by robots and/or by a specific set of User objects.
|
||||||
|
"""
|
||||||
Org = User.alias()
|
Org = User.alias()
|
||||||
org_users = (User
|
org_users = (User
|
||||||
.select(User.username)
|
.select(User.username)
|
||||||
.join(TeamMember)
|
.join(TeamMember)
|
||||||
.join(Team)
|
.join(Team)
|
||||||
.join(Org, on=(Org.id == Team.organization))
|
.where(Team.organization == org)
|
||||||
.where(Org.username == orgname)
|
|
||||||
.distinct())
|
.distinct())
|
||||||
|
|
||||||
|
if not include_robots:
|
||||||
|
org_users = org_users.where(User.robot == False)
|
||||||
|
|
||||||
|
if users_filter is not None:
|
||||||
|
ids_list = [u.id for u in users_filter if u is not None]
|
||||||
|
if not ids_list:
|
||||||
|
return set()
|
||||||
|
|
||||||
|
org_users = org_users.where(User.id << ids_list)
|
||||||
|
|
||||||
return {user.username for user in org_users}
|
return {user.username for user in org_users}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -73,6 +73,9 @@ class RepositoryUserPermissionList(RepositoryParamResource):
|
||||||
# This repository isn't under an org
|
# This repository isn't under an org
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# Load the permissions.
|
||||||
|
repo_perms = model.user.get_all_repo_users(namespace, repository)
|
||||||
|
|
||||||
# Determine how to wrap the role(s).
|
# Determine how to wrap the role(s).
|
||||||
def wrapped_role_view(repo_perm):
|
def wrapped_role_view(repo_perm):
|
||||||
return wrap_role_view_user(role_view(repo_perm), repo_perm.user)
|
return wrap_role_view_user(role_view(repo_perm), repo_perm.user)
|
||||||
|
@ -80,20 +83,17 @@ class RepositoryUserPermissionList(RepositoryParamResource):
|
||||||
role_view_func = wrapped_role_view
|
role_view_func = wrapped_role_view
|
||||||
|
|
||||||
if org:
|
if org:
|
||||||
org_members = model.organization.get_organization_member_set(namespace)
|
users_filter = {perm.user for perm in repo_perms}
|
||||||
|
org_members = model.organization.get_organization_member_set(org, users_filter=users_filter)
|
||||||
current_func = role_view_func
|
current_func = role_view_func
|
||||||
|
|
||||||
def wrapped_role_org_view(repo_perm):
|
def wrapped_role_org_view(repo_perm):
|
||||||
return wrap_role_view_org(current_func(repo_perm), repo_perm.user,
|
return wrap_role_view_org(current_func(repo_perm), repo_perm.user, org_members)
|
||||||
org_members)
|
|
||||||
|
|
||||||
role_view_func = wrapped_role_org_view
|
role_view_func = wrapped_role_org_view
|
||||||
|
|
||||||
# Load and return the permissions.
|
|
||||||
repo_perms = model.user.get_all_repo_users(namespace, repository)
|
|
||||||
return {
|
return {
|
||||||
'permissions': {perm.user.username: role_view_func(perm)
|
'permissions': {perm.user.username: role_view_func(perm) for perm in repo_perms}
|
||||||
for perm in repo_perms}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -156,8 +156,8 @@ class RepositoryUserPermission(RepositoryParamResource):
|
||||||
perm_view = wrap_role_view_user(role_view(perm), perm.user)
|
perm_view = wrap_role_view_user(role_view(perm), perm.user)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
model.organization.get_organization(namespace)
|
org = model.organization.get_organization(namespace)
|
||||||
org_members = model.organization.get_organization_member_set(namespace)
|
org_members = model.organization.get_organization_member_set(org, users_filter={perm.user})
|
||||||
perm_view = wrap_role_view_org(perm_view, perm.user, org_members)
|
perm_view = wrap_role_view_org(perm_view, perm.user, org_members)
|
||||||
except model.InvalidOrganizationException:
|
except model.InvalidOrganizationException:
|
||||||
# This repository is not part of an organization
|
# This repository is not part of an organization
|
||||||
|
@ -183,8 +183,8 @@ class RepositoryUserPermission(RepositoryParamResource):
|
||||||
perm_view = wrap_role_view_user(role_view(perm), perm.user)
|
perm_view = wrap_role_view_user(role_view(perm), perm.user)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
model.organization.get_organization(namespace)
|
org = model.organization.get_organization(namespace)
|
||||||
org_members = model.organization.get_organization_member_set(namespace)
|
org_members = model.organization.get_organization_member_set(org, users_filter={perm.user})
|
||||||
perm_view = wrap_role_view_org(perm_view, perm.user, org_members)
|
perm_view = wrap_role_view_org(perm_view, perm.user, org_members)
|
||||||
except model.InvalidOrganizationException:
|
except model.InvalidOrganizationException:
|
||||||
# This repository is not part of an organization
|
# This repository is not part of an organization
|
||||||
|
|
|
@ -133,7 +133,10 @@ class PermissionPrototypeList(ApiResource):
|
||||||
raise NotFound()
|
raise NotFound()
|
||||||
|
|
||||||
permissions = model.permission.get_prototype_permissions(org)
|
permissions = model.permission.get_prototype_permissions(org)
|
||||||
org_members = model.organization.get_organization_member_set(orgname)
|
|
||||||
|
users_filter = ({p.activating_user for p in permissions} |
|
||||||
|
{p.delegate_user for p in permissions})
|
||||||
|
org_members = model.organization.get_organization_member_set(org, users_filter=users_filter)
|
||||||
return {'prototypes': [prototype_view(p, org_members) for p in permissions]}
|
return {'prototypes': [prototype_view(p, org_members) for p in permissions]}
|
||||||
|
|
||||||
raise Unauthorized()
|
raise Unauthorized()
|
||||||
|
@ -180,7 +183,9 @@ class PermissionPrototypeList(ApiResource):
|
||||||
prototype = model.permission.add_prototype_permission(org, role_name, activating_user,
|
prototype = model.permission.add_prototype_permission(org, role_name, activating_user,
|
||||||
delegate_user, delegate_team)
|
delegate_user, delegate_team)
|
||||||
log_prototype_action('create_prototype_permission', orgname, prototype)
|
log_prototype_action('create_prototype_permission', orgname, prototype)
|
||||||
org_members = model.organization.get_organization_member_set(orgname)
|
|
||||||
|
users_filter = {prototype.activating_user, prototype.delegate_user}
|
||||||
|
org_members = model.organization.get_organization_member_set(org, users_filter=users_filter)
|
||||||
return prototype_view(prototype, org_members)
|
return prototype_view(prototype, org_members)
|
||||||
|
|
||||||
raise Unauthorized()
|
raise Unauthorized()
|
||||||
|
@ -257,7 +262,9 @@ class PermissionPrototype(ApiResource):
|
||||||
|
|
||||||
log_prototype_action('modify_prototype_permission', orgname, prototype,
|
log_prototype_action('modify_prototype_permission', orgname, prototype,
|
||||||
original_role=existing.role.name)
|
original_role=existing.role.name)
|
||||||
org_members = model.organization.get_organization_member_set(orgname)
|
|
||||||
|
users_filter = {prototype.activating_user, prototype.delegate_user}
|
||||||
|
org_members = model.organization.get_organization_member_set(org, users_filter=users_filter)
|
||||||
return prototype_view(prototype, org_members)
|
return prototype_view(prototype, org_members)
|
||||||
|
|
||||||
raise Unauthorized()
|
raise Unauthorized()
|
||||||
|
|
Reference in a new issue