Add groups tab in project details view.
Add an extra tab "Groups" in the project details view which displays the groups which have a role on the project (the groups members of the project). The groups are displayed in a table which is an extension (inheritance) of the group table used in the Groups panel. An extra column is added to this table, displaying the roles of each group on project Change-Id: Ie6338c7e10b67900d5a553d0328b29bfd4a28212 Closes-Bug: #1785263
This commit is contained in:
parent
6e754e5dad
commit
7c80aba5ef
@ -0,0 +1,33 @@
|
|||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
from horizon import forms
|
||||||
|
from horizon import tables
|
||||||
|
|
||||||
|
from openstack_dashboard.dashboards.identity.groups \
|
||||||
|
import tables as groups_tables
|
||||||
|
|
||||||
|
|
||||||
|
class GroupsTable(groups_tables.GroupsTable):
|
||||||
|
"""Display groups of the project."""
|
||||||
|
roles = tables.Column(
|
||||||
|
lambda obj: ", ".join(getattr(obj, 'roles', [])),
|
||||||
|
verbose_name=_('Roles'),
|
||||||
|
form_field=forms.CharField(
|
||||||
|
widget=forms.Textarea(attrs={'rows': 4}),
|
||||||
|
required=False))
|
||||||
|
|
||||||
|
class Meta(object):
|
||||||
|
name = "groupstable"
|
||||||
|
verbose_name = _("Groups")
|
@ -18,6 +18,8 @@ from horizon import tabs
|
|||||||
|
|
||||||
from openstack_dashboard import api
|
from openstack_dashboard import api
|
||||||
|
|
||||||
|
from openstack_dashboard.dashboards.identity.projects.groups \
|
||||||
|
import tables as groups_tables
|
||||||
from openstack_dashboard.dashboards.identity.projects.users \
|
from openstack_dashboard.dashboards.identity.projects.users \
|
||||||
import tables as users_tables
|
import tables as users_tables
|
||||||
|
|
||||||
@ -169,6 +171,44 @@ class UsersTab(tabs.TableTab):
|
|||||||
return project_users.values()
|
return project_users.values()
|
||||||
|
|
||||||
|
|
||||||
|
class GroupsTab(tabs.TableTab):
|
||||||
|
"""Display groups member of the project. """
|
||||||
|
table_classes = (groups_tables.GroupsTable,)
|
||||||
|
name = _("Groups")
|
||||||
|
slug = "groups"
|
||||||
|
template_name = "horizon/common/_detail_table.html"
|
||||||
|
preload = False
|
||||||
|
|
||||||
|
def get_groupstable_data(self):
|
||||||
|
groups_in_project = []
|
||||||
|
project = self.tab_group.kwargs['project']
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Get project_groups_roles: {group_id: [role_id_1, role_id_2]}
|
||||||
|
project_groups_roles = api.keystone.get_project_groups_roles(
|
||||||
|
self.request,
|
||||||
|
project=project.id)
|
||||||
|
# Get global roles and groups
|
||||||
|
roles = api.keystone.role_list(self.request)
|
||||||
|
# For keystone.group_list, we do not give the project_id because it
|
||||||
|
# is ignored when called with admin creds.
|
||||||
|
groups = api.keystone.group_list(self.request)
|
||||||
|
groups = {group.id: group for group in groups}
|
||||||
|
except Exception:
|
||||||
|
exceptions.handle(self.request,
|
||||||
|
_("Unable to display the groups of this"
|
||||||
|
" project."))
|
||||||
|
else:
|
||||||
|
# Construct Groups list, adding the role attribute
|
||||||
|
for group_id in project_groups_roles:
|
||||||
|
group = groups[group_id]
|
||||||
|
group.roles = [role.name for role in roles
|
||||||
|
if role.id in project_groups_roles[group_id]]
|
||||||
|
groups_in_project.append(group)
|
||||||
|
|
||||||
|
return groups_in_project
|
||||||
|
|
||||||
|
|
||||||
class ProjectDetailTabs(tabs.DetailTabsGroup):
|
class ProjectDetailTabs(tabs.DetailTabsGroup):
|
||||||
slug = "project_details"
|
slug = "project_details"
|
||||||
tabs = (OverviewTab, UsersTab,)
|
tabs = (OverviewTab, UsersTab, GroupsTab,)
|
||||||
|
@ -1486,6 +1486,94 @@ class DetailProjectViewTests(test.BaseAdminViewTests):
|
|||||||
self.mock_enabled_quotas.assert_called_once_with(test.IsHttpRequest())
|
self.mock_enabled_quotas.assert_called_once_with(test.IsHttpRequest())
|
||||||
self.mock_role_list.assert_called_once_with(test.IsHttpRequest())
|
self.mock_role_list.assert_called_once_with(test.IsHttpRequest())
|
||||||
|
|
||||||
|
@test.create_mocks({api.keystone: ("tenant_get",
|
||||||
|
"get_project_groups_roles",
|
||||||
|
"role_list",
|
||||||
|
"group_list"),
|
||||||
|
quotas: ('enabled_quotas',)})
|
||||||
|
def test_detail_view_groups_tab(self):
|
||||||
|
project = self.tenants.first()
|
||||||
|
groups = self.groups.filter(domain_id=project.domain_id)
|
||||||
|
role_assignments = self.role_assignments.filter(
|
||||||
|
scope={'project': {'id': project.id}})
|
||||||
|
# {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_get_project_groups_roles.return_value = project_groups_roles
|
||||||
|
self.mock_group_list.return_value = groups
|
||||||
|
self.mock_role_list.return_value = self.roles.list()
|
||||||
|
|
||||||
|
# Get project details view on group tab
|
||||||
|
url = reverse('horizon:identity:projects:detail', args=[project.id])
|
||||||
|
detail_view = tabs.ProjectDetailTabs(self.request, group=project)
|
||||||
|
groups_tab_link = "?%s=%s" % (
|
||||||
|
detail_view.param_name,
|
||||||
|
detail_view.get_tab("groups").get_id()
|
||||||
|
)
|
||||||
|
url += groups_tab_link
|
||||||
|
|
||||||
|
res = self.client.get(url)
|
||||||
|
|
||||||
|
# Check the template expected has been used
|
||||||
|
self.assertTemplateUsed(res,
|
||||||
|
"horizon/common/_detail_table.html")
|
||||||
|
|
||||||
|
# Check the table content
|
||||||
|
groups_expected = {'1': ["_member_"], }
|
||||||
|
groups_id_observed = [group.id for group in
|
||||||
|
res.context["groupstable_table"].data]
|
||||||
|
|
||||||
|
# Check the group is displayed
|
||||||
|
self.assertItemsEqual(groups_id_observed, groups_expected.keys())
|
||||||
|
|
||||||
|
# Check the groups roles
|
||||||
|
for group in res.context["groupstable_table"].data:
|
||||||
|
self.assertEqual(groups_expected[group.id], group.roles)
|
||||||
|
|
||||||
|
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_groups_roles.assert_called_once_with(
|
||||||
|
test.IsHttpRequest(), project=project.id)
|
||||||
|
|
||||||
|
@test.create_mocks({api.keystone: ("tenant_get",
|
||||||
|
"get_project_groups_roles"),
|
||||||
|
quotas: ('enabled_quotas',)})
|
||||||
|
def test_detail_view_groups_tab_exception(self):
|
||||||
|
project = self.tenants.first()
|
||||||
|
|
||||||
|
# Prepare mocks
|
||||||
|
self.mock_tenant_get.return_value = project
|
||||||
|
self.mock_enabled_quotas.return_value = ('instances',)
|
||||||
|
self.mock_get_project_groups_roles.side_effect = \
|
||||||
|
self.exceptions.keystone
|
||||||
|
|
||||||
|
# Get project details view on group tab
|
||||||
|
url = reverse('horizon:identity:projects:detail', args=[project.id])
|
||||||
|
detail_view = tabs.ProjectDetailTabs(self.request, group=project)
|
||||||
|
groups_tab_link = "?%s=%s" % (
|
||||||
|
detail_view.param_name,
|
||||||
|
detail_view.get_tab("groups").get_id()
|
||||||
|
)
|
||||||
|
url += groups_tab_link
|
||||||
|
res = self.client.get(url)
|
||||||
|
|
||||||
|
# Check the projects table is empty
|
||||||
|
self.assertFalse(res.context["groupstable_table"].data)
|
||||||
|
# Check one error message is displayed
|
||||||
|
self.assertMessageCount(res, error=1)
|
||||||
|
|
||||||
|
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_get_project_groups_roles.assert_called_once_with(
|
||||||
|
test.IsHttpRequest(), project=project.id)
|
||||||
|
|
||||||
|
|
||||||
@tag('selenium')
|
@tag('selenium')
|
||||||
class SeleniumTests(test.SeleniumAdminTestCase, test.TestCase):
|
class SeleniumTests(test.SeleniumAdminTestCase, test.TestCase):
|
||||||
|
Loading…
Reference in New Issue
Block a user