Display users with role through group in users project details tab.
In the users tab of the project details view, the users table displays now the users which have a role on the project through a group. ie: if a group is member of the project, and if a user is a member of this group, then it will be displayed in the table even if it is not directly a member of the project. An extra column is added to the table: "role from group" which display the list of "role(group)" the user has on the project. To be able to test the membership of user to a project through a group, "user_group_membership" data has been added to keystone data. Change-Id: I968bad7d285acfaf7a8ccd7458593bbcad498ce2 Partial-Bug: #1785263
This commit is contained in:
parent
610eab4ba4
commit
6e754e5dad
|
@ -97,8 +97,51 @@ class UsersTab(tabs.TableTab):
|
|||
roles_list=roles
|
||||
)
|
||||
|
||||
def _get_users_from_groups(self, project_id, roles, project_users):
|
||||
"""Update with users which have role on project through a group.
|
||||
|
||||
:param project_id: ID of the project
|
||||
:param roles: list of roles from keystone
|
||||
:param project_users: list to be updated with the users found
|
||||
"""
|
||||
|
||||
# For keystone.group_list project_id is not passed as argument because
|
||||
# it is ignored when using admin credentials
|
||||
# Get all groups (to be able to find group name)
|
||||
groups = api.keystone.group_list(self.request)
|
||||
group_names = {group.id: group.name for group in groups}
|
||||
|
||||
# Get a dictionary {group_id: [role_id_1, role_id_2]}
|
||||
project_groups_roles = api.keystone.get_project_groups_roles(
|
||||
self.request,
|
||||
project=project_id)
|
||||
|
||||
for group_id in project_groups_roles:
|
||||
group_users = api.keystone.user_list(self.request,
|
||||
group=group_id)
|
||||
group_roles_names = [
|
||||
role.name for role in roles
|
||||
if role.id in project_groups_roles[group_id]]
|
||||
|
||||
roles_from_group = [(role_name, group_names[group_id])
|
||||
for role_name in group_roles_names]
|
||||
|
||||
for user in group_users:
|
||||
if user.id not in project_users:
|
||||
# New user: Add the user to the list
|
||||
project_users[user.id] = user
|
||||
project_users[user.id].roles = []
|
||||
project_users[user.id].roles_from_groups = []
|
||||
|
||||
# Add roles from group
|
||||
project_users[user.id].roles_from_groups.extend(
|
||||
roles_from_group)
|
||||
|
||||
def get_userstable_data(self):
|
||||
"""Get users with roles on the project."""
|
||||
"""Get users with roles on the project.
|
||||
|
||||
Roles can be applied directly on the project or through a group.
|
||||
"""
|
||||
project_users = {}
|
||||
project = self.tab_group.kwargs['project']
|
||||
|
||||
|
@ -112,6 +155,12 @@ class UsersTab(tabs.TableTab):
|
|||
roles=roles,
|
||||
project_users=project_users)
|
||||
|
||||
# Update project_users with users which have role indirectly on
|
||||
# the project, (through a group)
|
||||
self._get_users_from_groups(project_id=project.id,
|
||||
roles=roles,
|
||||
project_users=project_users)
|
||||
|
||||
except Exception:
|
||||
exceptions.handle(self.request,
|
||||
_("Unable to display the users of this project.")
|
||||
|
|
|
@ -1350,6 +1350,14 @@ class DetailProjectViewTests(test.BaseAdminViewTests):
|
|||
self.tenant.id)
|
||||
self.mock_enabled_quotas.assert_called_once_with(test.IsHttpRequest())
|
||||
|
||||
def _get_users_in_group(self, group_id):
|
||||
users_in_group = [membership["user_id"] for membership in
|
||||
self.user_group_membership.list()
|
||||
if membership["group_id"] == group_id]
|
||||
users = [user for user in self.users.list() if
|
||||
user.id in users_in_group]
|
||||
return users
|
||||
|
||||
def _project_user_roles(self, role_assignments):
|
||||
roles = {}
|
||||
for role_assignment in role_assignments:
|
||||
|
@ -1358,25 +1366,45 @@ class DetailProjectViewTests(test.BaseAdminViewTests):
|
|||
role_assignment.role["id"]]
|
||||
return roles
|
||||
|
||||
def _project_group_roles(self, role_assignments):
|
||||
roles = {}
|
||||
for role_assignment in role_assignments:
|
||||
if hasattr(role_assignment, 'group'):
|
||||
roles[role_assignment.group['id']] = [
|
||||
role_assignment.role["id"]]
|
||||
return roles
|
||||
|
||||
@test.create_mocks({api.keystone: ('tenant_get',
|
||||
'user_list',
|
||||
'get_project_users_roles',
|
||||
'role_list',),
|
||||
'get_project_groups_roles',
|
||||
'role_list',
|
||||
'group_list'),
|
||||
quotas: ('enabled_quotas',)})
|
||||
def test_detail_view_users_tab(self):
|
||||
project = self.tenants.first()
|
||||
users = self.users.filter(domain_id=project.domain_id)
|
||||
groups = self.groups.filter(domain_id=project.domain_id)
|
||||
role_assignments = self.role_assignments.filter(
|
||||
scope={'project': {'id': project.id}})
|
||||
# {user_id: [role_id1, role_id2]} as returned by the api
|
||||
project_users_roles = self._project_user_roles(role_assignments)
|
||||
# {group_id: [role_id1, role_id2]} as returned by the api
|
||||
project_groups_roles = self._project_group_roles(role_assignments)
|
||||
|
||||
# Prepare mocks
|
||||
self.mock_tenant_get.return_value = project
|
||||
self.mock_enabled_quotas.return_value = ('instances',)
|
||||
self.mock_role_list.return_value = self.roles.list()
|
||||
|
||||
self.mock_user_list.return_value = users
|
||||
def _user_list_side_effect(request, group=None):
|
||||
if group:
|
||||
return self._get_users_in_group(group)
|
||||
return users
|
||||
self.mock_user_list.side_effect = _user_list_side_effect
|
||||
self.mock_group_list.return_value = groups
|
||||
self.mock_get_project_users_roles.return_value = project_users_roles
|
||||
self.mock_get_project_groups_roles.return_value = project_groups_roles
|
||||
|
||||
# Get project details view on user tab
|
||||
url = PROJECT_DETAIL_URL % [project.id]
|
||||
|
@ -1392,27 +1420,40 @@ class DetailProjectViewTests(test.BaseAdminViewTests):
|
|||
|
||||
# Check the content of the table
|
||||
users_expected = {
|
||||
'1': {'roles': ['admin'], },
|
||||
'2': {'roles': ['_member_'], },
|
||||
'3': {'roles': ['_member_'], },
|
||||
'1': {'roles': ['admin'],
|
||||
'roles_from_groups': [('_member_', 'group_one'), ], },
|
||||
'2': {'roles': ['_member_'],
|
||||
'roles_from_groups': [], },
|
||||
'3': {'roles': ['_member_'],
|
||||
'roles_from_groups': [('_member_', 'group_one'), ], },
|
||||
'4': {'roles': [],
|
||||
'roles_from_groups': [('_member_', 'group_one'), ], }
|
||||
}
|
||||
|
||||
users_id_observed = [user.id for user in
|
||||
res.context["userstable_table"].data]
|
||||
self.assertItemsEqual(users_expected.keys(), users_id_observed)
|
||||
|
||||
# Check the users roles
|
||||
# Check the users groups and roles
|
||||
for user in res.context["userstable_table"].data:
|
||||
self.assertItemsEqual(users_expected[user.id]["roles"],
|
||||
user.roles)
|
||||
self.assertItemsEqual(users_expected[user.id]["roles_from_groups"],
|
||||
user.roles_from_groups)
|
||||
|
||||
self.mock_tenant_get.assert_called_once_with(test.IsHttpRequest(),
|
||||
self.tenant.id)
|
||||
self.mock_enabled_quotas.assert_called_once_with(test.IsHttpRequest())
|
||||
self.mock_role_list.assert_called_once_with(test.IsHttpRequest())
|
||||
self.mock_group_list.assert_called_once_with(test.IsHttpRequest())
|
||||
self.mock_get_project_users_roles.assert_called_once_with(
|
||||
test.IsHttpRequest(), project=project.id)
|
||||
self.mock_user_list.assert_called_once_with(test.IsHttpRequest())
|
||||
self.mock_get_project_groups_roles.assert_called_once_with(
|
||||
test.IsHttpRequest(), project=project.id)
|
||||
calls = [mock.call(test.IsHttpRequest()),
|
||||
mock.call(test.IsHttpRequest(), group="1"), ]
|
||||
|
||||
self.mock_user_list.assert_has_calls(calls)
|
||||
|
||||
@test.create_mocks({api.keystone: ("tenant_get",
|
||||
"role_list",),
|
||||
|
|
|
@ -28,6 +28,14 @@ class UsersTable(users_tables.UsersTable):
|
|||
widget=forms.Textarea(attrs={'rows': 4}),
|
||||
required=False))
|
||||
|
||||
groups_roles = tables.Column(
|
||||
lambda obj: ", ".join("%s (%s)" % (role, group) for role, group in
|
||||
getattr(obj, 'roles_from_groups')),
|
||||
verbose_name=_('Roles from Groups'),
|
||||
form_field=forms.CharField(
|
||||
widget=forms.Textarea(attrs={'rows': 4}),
|
||||
required=False))
|
||||
|
||||
class Meta(object):
|
||||
name = "userstable"
|
||||
verbose_name = _("Users")
|
||||
|
|
|
@ -127,6 +127,7 @@ def data(TEST):
|
|||
TEST.domains = utils.TestDataContainer()
|
||||
TEST.users = utils.TestDataContainer()
|
||||
TEST.groups = utils.TestDataContainer()
|
||||
TEST.user_group_membership = utils.TestDataContainer()
|
||||
TEST.tenants = utils.TestDataContainer()
|
||||
TEST.role_assignments = utils.TestDataContainer()
|
||||
TEST.roles = utils.TestDataContainer()
|
||||
|
@ -252,6 +253,19 @@ def data(TEST):
|
|||
|
||||
TEST.groups.add(group, group2, group3, group4, group5)
|
||||
|
||||
user_group_membership = {"user_id": "1", "group_id": "1"}
|
||||
TEST.user_group_membership.add(user_group_membership)
|
||||
user_group_membership = {"user_id": "1", "group_id": "2"}
|
||||
TEST.user_group_membership.add(user_group_membership)
|
||||
user_group_membership = {"user_id": "2", "group_id": "2"}
|
||||
TEST.user_group_membership.add(user_group_membership)
|
||||
user_group_membership = {"user_id": "2", "group_id": "3"}
|
||||
TEST.user_group_membership.add(user_group_membership)
|
||||
user_group_membership = {"user_id": "3", "group_id": "1"}
|
||||
TEST.user_group_membership.add(user_group_membership)
|
||||
user_group_membership = {"user_id": "4", "group_id": "1"}
|
||||
TEST.user_group_membership.add(user_group_membership)
|
||||
|
||||
role_assignments_dict = {'user': {'id': '1'},
|
||||
'role': {'id': '1'},
|
||||
'scope': {'project': {'id': '1'}}}
|
||||
|
|
Loading…
Reference in New Issue