Add role assignment tab in the user details view.
Add an extra tab "role assignments" in the user details view which displays all the project/role domain/role of the current user. The role assignments are displayed in a table. The project/domain column is clickable and forward to the project /domain detail view. Change-Id: Iefe17856e60b84d089f722c3a30e9ede21d8ce47 Partial-Bug: #1792524 Co-Authored-By: Akihiro Motoki <amotoki@gmail.com>
This commit is contained in:
parent
254e3791d3
commit
ba82055f05
@ -0,0 +1,93 @@
|
|||||||
|
# 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 import urls
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
from horizon import forms
|
||||||
|
from horizon import tables
|
||||||
|
|
||||||
|
from openstack_dashboard import policy
|
||||||
|
|
||||||
|
|
||||||
|
def get_project_name(datum):
|
||||||
|
if "project" in datum.scope:
|
||||||
|
if "name" in datum.scope["project"]:
|
||||||
|
return datum.scope["project"]["name"]
|
||||||
|
return datum.scope["project"]["id"]
|
||||||
|
|
||||||
|
|
||||||
|
def get_project_link(datum, request):
|
||||||
|
if "project" not in datum.scope:
|
||||||
|
return
|
||||||
|
if policy.check((("identity", "identity:get_project"),),
|
||||||
|
request, target={"project": datum}):
|
||||||
|
return urls.reverse("horizon:identity:projects:detail",
|
||||||
|
args=(datum.scope["project"]["id"],))
|
||||||
|
|
||||||
|
|
||||||
|
def get_domain_name(datum):
|
||||||
|
if "domain" in datum.scope:
|
||||||
|
if "name" in datum.scope["domain"]:
|
||||||
|
return datum.scope["domain"]["name"]
|
||||||
|
return datum.scope["domain"]["id"]
|
||||||
|
|
||||||
|
|
||||||
|
def get_system_scope(datum):
|
||||||
|
if "system" in datum.scope:
|
||||||
|
return ', '.join(datum.scope["system"].keys())
|
||||||
|
|
||||||
|
|
||||||
|
def get_role_name(datum):
|
||||||
|
if "name" in datum.role:
|
||||||
|
return datum.role["name"]
|
||||||
|
return datum.role["id"]
|
||||||
|
|
||||||
|
|
||||||
|
class RoleAssignmentsTable(tables.DataTable):
|
||||||
|
|
||||||
|
project = tables.WrappingColumn(get_project_name,
|
||||||
|
verbose_name=_('Project'),
|
||||||
|
link=get_project_link,
|
||||||
|
form_field=forms.CharField(max_length=64))
|
||||||
|
|
||||||
|
domain = tables.WrappingColumn(get_domain_name,
|
||||||
|
verbose_name=_('Domain'),
|
||||||
|
form_field=forms.CharField(max_length=64))
|
||||||
|
|
||||||
|
system = tables.WrappingColumn(get_system_scope,
|
||||||
|
verbose_name=_('System Scope'),
|
||||||
|
form_field=forms.CharField(max_length=64))
|
||||||
|
|
||||||
|
role = tables.Column(get_role_name,
|
||||||
|
verbose_name=_('Role'),
|
||||||
|
form_field=forms.CharField(
|
||||||
|
widget=forms.Textarea(attrs={'rows': 4}),
|
||||||
|
required=False))
|
||||||
|
|
||||||
|
def get_object_id(self, datum):
|
||||||
|
"""Identifier of the role assignment."""
|
||||||
|
|
||||||
|
# Role assignment doesn't have identifier so one will be created
|
||||||
|
# from the identifier of scope, user and role. This will guaranty the
|
||||||
|
# unicity.
|
||||||
|
scope_id = ""
|
||||||
|
if "project" in datum.scope:
|
||||||
|
scope_id = datum.scope["project"]["id"]
|
||||||
|
elif "domain" in datum.scope:
|
||||||
|
scope_id = datum.scope["domain"]["id"]
|
||||||
|
|
||||||
|
return "%s%s%s" % (datum.user["id"], datum.role["id"], scope_id)
|
||||||
|
|
||||||
|
class Meta(object):
|
||||||
|
name = "roleassignmentstable"
|
||||||
|
verbose_name = _("Role assignments")
|
@ -13,8 +13,13 @@
|
|||||||
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
from horizon import exceptions
|
||||||
from horizon import tabs
|
from horizon import tabs
|
||||||
|
|
||||||
|
from openstack_dashboard import api
|
||||||
|
from openstack_dashboard.dashboards.identity.users.role_assignments \
|
||||||
|
import tables as role_assignments_tables
|
||||||
|
|
||||||
|
|
||||||
class OverviewTab(tabs.Tab):
|
class OverviewTab(tabs.Tab):
|
||||||
"""Overview of the user.
|
"""Overview of the user.
|
||||||
@ -29,6 +34,33 @@ class OverviewTab(tabs.Tab):
|
|||||||
return {"user": self.tab_group.kwargs['user']}
|
return {"user": self.tab_group.kwargs['user']}
|
||||||
|
|
||||||
|
|
||||||
|
class RoleAssignmentsTab(tabs.TableTab):
|
||||||
|
"""Role assignment of the user to domain/project."""
|
||||||
|
table_classes = (role_assignments_tables.RoleAssignmentsTable,)
|
||||||
|
name = _("Role assignments")
|
||||||
|
slug = "roleassignments"
|
||||||
|
template_name = "horizon/common/_detail_table.html"
|
||||||
|
preload = False
|
||||||
|
|
||||||
|
def get_roleassignmentstable_data(self):
|
||||||
|
user = self.tab_group.kwargs['user']
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Get all the roles of the user
|
||||||
|
user_roles = api.keystone.role_assignments_list(
|
||||||
|
self.request, user=user, include_subtree=False,
|
||||||
|
include_names=True)
|
||||||
|
|
||||||
|
return user_roles
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
exceptions.handle(
|
||||||
|
self.request,
|
||||||
|
_("Unable to display the role assignments of this user."))
|
||||||
|
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
class UserDetailTabs(tabs.DetailTabsGroup):
|
class UserDetailTabs(tabs.DetailTabsGroup):
|
||||||
slug = "user_details"
|
slug = "user_details"
|
||||||
tabs = (OverviewTab,)
|
tabs = (OverviewTab, RoleAssignmentsTab,)
|
||||||
|
@ -922,6 +922,96 @@ class UsersViewTests(test.BaseAdminViewTests):
|
|||||||
self.mock_tenant_get.assert_called_once_with(test.IsHttpRequest(),
|
self.mock_tenant_get.assert_called_once_with(test.IsHttpRequest(),
|
||||||
user.project_id)
|
user.project_id)
|
||||||
|
|
||||||
|
@test.create_mocks({api.keystone: ('domain_get',
|
||||||
|
'user_get',
|
||||||
|
'tenant_get',
|
||||||
|
'role_assignments_list')})
|
||||||
|
def test_detail_view_role_assignments_tab(self):
|
||||||
|
"""Test the role assignments tab of the detail view ."""
|
||||||
|
domain = self._get_default_domain()
|
||||||
|
user = self.users.get(id="1")
|
||||||
|
tenant = self.tenants.get(id=user.project_id)
|
||||||
|
role_assignments = self.role_assignments.filter(user={'id': user.id})
|
||||||
|
|
||||||
|
self.mock_domain_get.return_value = domain
|
||||||
|
self.mock_user_get.return_value = user
|
||||||
|
self.mock_tenant_get.return_value = tenant
|
||||||
|
self.mock_role_assignments_list.return_value = role_assignments
|
||||||
|
|
||||||
|
# Url of the role assignment tab of the detail view
|
||||||
|
url = USER_DETAIL_URL % [user.id]
|
||||||
|
detail_view = tabs.UserDetailTabs(self.request, user=user)
|
||||||
|
role_assignments_tab_link = "?%s=%s" % (
|
||||||
|
detail_view.param_name,
|
||||||
|
detail_view.get_tab("roleassignments").get_id()
|
||||||
|
)
|
||||||
|
url += role_assignments_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 expected data
|
||||||
|
role_assignments_expected = role_assignments
|
||||||
|
role_assignments_observed = res.context["table"].data
|
||||||
|
self.assertItemsEqual(role_assignments_expected,
|
||||||
|
role_assignments_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_role_assignments_list.assert_called_once_with(
|
||||||
|
test.IsHttpRequest(), user=user, include_subtree=False,
|
||||||
|
include_names=True)
|
||||||
|
|
||||||
|
@test.create_mocks({api.keystone: ('domain_get',
|
||||||
|
'user_get',
|
||||||
|
'tenant_get',
|
||||||
|
'role_assignments_list')})
|
||||||
|
def test_detail_view_role_assignments_tab_with_exception(self):
|
||||||
|
"""Test the role assignments tab with exception.
|
||||||
|
|
||||||
|
The table is displayed empty and an error message pop if the role
|
||||||
|
assignment 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_role_assignments_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)
|
||||||
|
role_assignments_tab_link = "?%s=%s" % (
|
||||||
|
detail_view.param_name,
|
||||||
|
detail_view.get_tab("roleassignments").get_id()
|
||||||
|
)
|
||||||
|
url += role_assignments_tab_link
|
||||||
|
|
||||||
|
res = self.client.get(url)
|
||||||
|
|
||||||
|
# Check the role assignment 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_role_assignments_list.assert_called_once_with(
|
||||||
|
test.IsHttpRequest(), user=user, include_subtree=False,
|
||||||
|
include_names=True)
|
||||||
|
|
||||||
@test.create_mocks({api.keystone: ('user_get',
|
@test.create_mocks({api.keystone: ('user_get',
|
||||||
'domain_get',
|
'domain_get',
|
||||||
'tenant_list',)})
|
'tenant_list',)})
|
||||||
|
Loading…
x
Reference in New Issue
Block a user