diff --git a/openstack_dashboard/dashboards/identity/users/groups/__init__.py b/openstack_dashboard/dashboards/identity/users/groups/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/openstack_dashboard/dashboards/identity/users/groups/tables.py b/openstack_dashboard/dashboards/identity/users/groups/tables.py new file mode 100644 index 0000000000..e83c355576 --- /dev/null +++ b/openstack_dashboard/dashboards/identity/users/groups/tables.py @@ -0,0 +1,23 @@ +# 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 openstack_dashboard.dashboards.identity.groups \ + import tables as groups_tables + + +class GroupsTable(groups_tables.GroupsTable): + + class Meta(object): + name = "groupstable" + verbose_name = _("Groups") diff --git a/openstack_dashboard/dashboards/identity/users/tabs.py b/openstack_dashboard/dashboards/identity/users/tabs.py index 4ac8f45a23..f7e197b352 100644 --- a/openstack_dashboard/dashboards/identity/users/tabs.py +++ b/openstack_dashboard/dashboards/identity/users/tabs.py @@ -17,6 +17,8 @@ from horizon import exceptions from horizon import tabs from openstack_dashboard import api +from openstack_dashboard.dashboards.identity.users.groups \ + import tables as groups_tables from openstack_dashboard.dashboards.identity.users.role_assignments \ import tables as role_assignments_tables @@ -61,6 +63,27 @@ class RoleAssignmentsTab(tabs.TableTab): return [] +class GroupsTab(tabs.TableTab): + """Groups of the user.""" + table_classes = (groups_tables.GroupsTable,) + name = _("Groups") + slug = "groups" + template_name = "horizon/common/_detail_table.html" + preload = False + + def get_groupstable_data(self): + user_groups = [] + user = self.tab_group.kwargs['user'] + + try: + user_groups = api.keystone.group_list(self.request, user=user.id) + except Exception: + exceptions.handle(self.request, + _("Unable to display the groups of this user.")) + + return user_groups + + class UserDetailTabs(tabs.DetailTabsGroup): slug = "user_details" - tabs = (OverviewTab, RoleAssignmentsTab,) + tabs = (OverviewTab, RoleAssignmentsTab, GroupsTab,) diff --git a/openstack_dashboard/dashboards/identity/users/tests.py b/openstack_dashboard/dashboards/identity/users/tests.py index 280aa4877d..7f36e350d6 100644 --- a/openstack_dashboard/dashboards/identity/users/tests.py +++ b/openstack_dashboard/dashboards/identity/users/tests.py @@ -1012,6 +1012,88 @@ class UsersViewTests(test.BaseAdminViewTests): test.IsHttpRequest(), user=user, include_subtree=False, include_names=True) + @test.create_mocks({api.keystone: ('domain_get', + 'user_get', + 'tenant_get', + 'group_list')}) + def test_detail_view_groups_tab(self): + """Test the groups tab of the detail view .""" + domain = self._get_default_domain() + user = self.users.get(id="1") + tenant = self.tenants.get(id=user.project_id) + groups = self.groups.list() + + self.mock_domain_get.return_value = domain + self.mock_user_get.return_value = user + self.mock_tenant_get.return_value = tenant + self.mock_group_list.return_value = groups + + # Url of the role assignment tab of the detail view + url = USER_DETAIL_URL % [user.id] + detail_view = tabs.UserDetailTabs(self.request, user=user) + group_tab_link = "?%s=%s" % (detail_view.param_name, + detail_view.get_tab("groups").get_id()) + url += group_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 contains the good data + groups_expected = groups + groups_observed = res.context["table"].data + self.assertItemsEqual(groups_expected, groups_observed) + + self.mock_domain_get.assert_called_once_with(test.IsHttpRequest(), '1') + self.mock_user_get.assert_called_once_with(test.IsHttpRequest(), '1', + admin=False) + self.mock_tenant_get.assert_called_once_with(test.IsHttpRequest(), + user.project_id) + self.mock_group_list.assert_called_once_with(test.IsHttpRequest(), + user=user.id) + + @test.create_mocks({api.keystone: ('domain_get', + 'user_get', + 'tenant_get', + 'group_list')}) + def test_detail_view_groups_tab_with_exception(self): + """Test the groups tab of the detail view . + + The table is displayed empty and an error message pop if the groups + request fails. + """ + domain = self._get_default_domain() + user = self.users.get(id="1") + tenant = self.tenants.get(id=user.project_id) + + self.mock_domain_get.return_value = domain + self.mock_user_get.return_value = user + self.mock_tenant_get.return_value = tenant + self.mock_group_list.side_effect = self.exceptions.keystone + + # Url of the role assignment tab of the detail view + url = USER_DETAIL_URL % [user.id] + detail_view = tabs.UserDetailTabs(self.request, user=user) + group_tab_link = "?%s=%s" % (detail_view.param_name, + detail_view.get_tab("groups").get_id()) + url += group_tab_link + + res = self.client.get(url) + + # Check the groups table is empty + self.assertEqual(res.context["table"].data, []) + # Check one error message is displayed + self.assertMessageCount(res, error=1) + + self.mock_domain_get.assert_called_once_with(test.IsHttpRequest(), '1') + self.mock_user_get.assert_called_once_with(test.IsHttpRequest(), '1', + admin=False) + self.mock_tenant_get.assert_called_once_with(test.IsHttpRequest(), + user.project_id) + self.mock_group_list.assert_called_once_with(test.IsHttpRequest(), + user=user.id) + @test.create_mocks({api.keystone: ('user_get', 'domain_get', 'tenant_list',)})