Merge "Add groups tab in project details view."
This commit is contained in:
commit
0202d17c88
@ -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