Show domain info in project and user detail panel

Domain info in the user detail panel was previously displayed
but it has been broken after the user detail panel was tabbified.
This commit fixes the handling of context data. This covers
domain_name, project_name and extras.
Similar change is applied to the project detail panel too.

Change-Id: I575ae9697783c36fdae5dd397d6783b979d0c4a6
Closes-Bug: #1809284
This commit is contained in:
Akihiro Motoki 2018-12-21 01:58:16 +09:00
parent f02e7c5ade
commit 3a584a90c1
7 changed files with 135 additions and 68 deletions

View File

@ -17,6 +17,7 @@ from horizon import exceptions
from horizon import tabs
from openstack_dashboard import api
from openstack_dashboard import policy
from openstack_dashboard.dashboards.identity.projects.groups \
import tables as groups_tables
@ -32,15 +33,36 @@ class OverviewTab(tabs.Tab):
def get_context_data(self, request):
project = self.tab_group.kwargs['project']
context = {"project": project}
return {
"project": project,
"domain_name": self._get_domain_name(project),
"extras": self._get_extras(project),
}
def _get_domain_name(self, project):
domain_name = ''
if api.keystone.VERSIONS.active >= 3:
try:
if policy.check((("identity", "identity:get_domain"),),
self.request):
domain = api.keystone.domain_get(
self.request, project.domain_id)
domain_name = domain.name
else:
domain = api.keystone.get_default_domain(self.request)
domain_name = domain.get('name')
except Exception:
exceptions.handle(self.request,
_('Unable to retrieve project domain.'))
return domain_name
def _get_extras(self, project):
if api.keystone.VERSIONS.active >= 3:
extra_info = getattr(settings, 'PROJECT_TABLE_EXTRA_INFO', {})
context['extras'] = dict(
(display_key, getattr(project, key, ''))
for key, display_key in extra_info.items())
return context
return dict((display_key, getattr(project, key, ''))
for key, display_key in extra_info.items())
else:
return {}
class UsersTab(tabs.TableTab):

View File

@ -2,14 +2,20 @@
<div class="detail">
<dl class="dl-horizontal">
<dt>{% trans "Project Name" %}</dt>
<dt>{% trans "Name" %}</dt>
<dd data-display="{{ project.name|default:project.id }}">{{ project.name }}</dd>
<dt>{% trans "Project ID" %}</dt>
<dt>{% trans "ID" %}</dt>
<dd>{{ project.id }}</dd>
{% if domain_name %}
<dt>{% trans "Domain Name" %}</dt>
<dd>{{ domain_name }}</dd>
{% endif %}
<dt>{% trans "Domain ID" %}</dt>
<dd>{{ project.domain_id }}</dd>
<dt>{% trans "Enabled" %}</dt>
<dd>{{ project.enabled|yesno|capfirst }}</dd>
<dt>{% trans "Description" %}</dt>
<dd>{{ project.description|default:_("None") }}</dd>
<dd>{{ project.description|default:_("-") }}</dd>
{% if extras %}
{% for key, value in extras.items %}
<dt>{{ key }}</dt>

View File

@ -1286,12 +1286,14 @@ class UsageViewTests(test.BaseAdminViewTests):
class DetailProjectViewTests(test.BaseAdminViewTests):
@test.create_mocks({api.keystone: ('tenant_get',),
@test.create_mocks({api.keystone: ('tenant_get', 'domain_get'),
quotas: ('enabled_quotas',)})
def test_detail_view(self):
project = self.tenants.first()
domain = self.domains.first()
self.mock_tenant_get.return_value = project
self.mock_domain_get.return_value = domain
self.mock_enabled_quotas.return_value = ('instances',)
res = self.client.get(PROJECT_DETAIL_URL, args=[project.id])
@ -1304,6 +1306,8 @@ class DetailProjectViewTests(test.BaseAdminViewTests):
self.mock_tenant_get.assert_called_once_with(test.IsHttpRequest(),
self.tenant.id)
self.mock_domain_get.assert_called_once_with(test.IsHttpRequest(),
domain.id)
self.mock_enabled_quotas.assert_called_once_with(test.IsHttpRequest())
@test.create_mocks({api.keystone: ('tenant_get',)})
@ -1319,7 +1323,7 @@ class DetailProjectViewTests(test.BaseAdminViewTests):
self.mock_tenant_get.assert_called_once_with(test.IsHttpRequest(),
self.tenant.id)
@test.create_mocks({api.keystone: ('tenant_get',),
@test.create_mocks({api.keystone: ('tenant_get', 'domain_get'),
quotas: ('enabled_quotas',)})
def test_detail_view_overview_tab(self):
"""Test the overview tab of the detail view .
@ -1327,8 +1331,10 @@ class DetailProjectViewTests(test.BaseAdminViewTests):
Test the overview tab using directly the url targeting the tab.
"""
project = self.tenants.first()
domain = self.domains.first()
self.mock_tenant_get.return_value = project
self.mock_domain_get.return_value = domain
self.mock_enabled_quotas.return_value = ('instances',)
# Url of the overview tab of the detail view
@ -1348,6 +1354,8 @@ class DetailProjectViewTests(test.BaseAdminViewTests):
self.mock_tenant_get.assert_called_once_with(test.IsHttpRequest(),
self.tenant.id)
self.mock_domain_get.assert_called_once_with(test.IsHttpRequest(),
domain.id)
self.mock_enabled_quotas.assert_called_once_with(test.IsHttpRequest())
def _get_users_in_group(self, group_id):
@ -1375,6 +1383,7 @@ class DetailProjectViewTests(test.BaseAdminViewTests):
return roles
@test.create_mocks({api.keystone: ('tenant_get',
'domain_get',
'user_list',
'get_project_users_roles',
'get_project_groups_roles',
@ -1383,6 +1392,7 @@ class DetailProjectViewTests(test.BaseAdminViewTests):
quotas: ('enabled_quotas',)})
def test_detail_view_users_tab(self):
project = self.tenants.first()
domain = self.domains.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(
@ -1394,6 +1404,7 @@ class DetailProjectViewTests(test.BaseAdminViewTests):
# Prepare mocks
self.mock_tenant_get.return_value = project
self.mock_domain_get.return_value = domain
self.mock_enabled_quotas.return_value = ('instances',)
self.mock_role_list.return_value = self.roles.list()
@ -1443,6 +1454,8 @@ class DetailProjectViewTests(test.BaseAdminViewTests):
self.mock_tenant_get.assert_called_once_with(test.IsHttpRequest(),
self.tenant.id)
self.mock_domain_get.assert_called_once_with(test.IsHttpRequest(),
domain.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())
@ -1456,13 +1469,16 @@ class DetailProjectViewTests(test.BaseAdminViewTests):
self.mock_user_list.assert_has_calls(calls)
@test.create_mocks({api.keystone: ("tenant_get",
"domain_get",
"role_list",),
quotas: ('enabled_quotas',)})
def test_detail_view_users_tab_exception(self):
project = self.tenants.first()
domain = self.domains.first()
# Prepare mocks
self.mock_tenant_get.return_value = project
self.mock_domain_get.return_value = domain
self.mock_enabled_quotas.return_value = ('instances',)
self.mock_role_list.side_effect = self.exceptions.keystone
@ -1483,16 +1499,20 @@ class DetailProjectViewTests(test.BaseAdminViewTests):
self.mock_tenant_get.assert_called_once_with(test.IsHttpRequest(),
self.tenant.id)
self.mock_domain_get.assert_called_once_with(test.IsHttpRequest(),
domain.id)
self.mock_enabled_quotas.assert_called_once_with(test.IsHttpRequest())
self.mock_role_list.assert_called_once_with(test.IsHttpRequest())
@test.create_mocks({api.keystone: ("tenant_get",
"domain_get",
"get_project_groups_roles",
"role_list",
"group_list"),
quotas: ('enabled_quotas',)})
def test_detail_view_groups_tab(self):
project = self.tenants.first()
domain = self.domains.first()
groups = self.groups.filter(domain_id=project.domain_id)
role_assignments = self.role_assignments.filter(
scope={'project': {'id': project.id}})
@ -1501,6 +1521,7 @@ class DetailProjectViewTests(test.BaseAdminViewTests):
# Prepare mocks
self.mock_tenant_get.return_value = project
self.mock_domain_get.return_value = domain
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
@ -1535,6 +1556,8 @@ class DetailProjectViewTests(test.BaseAdminViewTests):
self.mock_tenant_get.assert_called_once_with(test.IsHttpRequest(),
self.tenant.id)
self.mock_domain_get.assert_called_once_with(test.IsHttpRequest(),
domain.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())
@ -1542,13 +1565,16 @@ class DetailProjectViewTests(test.BaseAdminViewTests):
test.IsHttpRequest(), project=project.id)
@test.create_mocks({api.keystone: ("tenant_get",
"domain_get",
"get_project_groups_roles"),
quotas: ('enabled_quotas',)})
def test_detail_view_groups_tab_exception(self):
project = self.tenants.first()
domain = self.domains.first()
# Prepare mocks
self.mock_tenant_get.return_value = project
self.mock_domain_get.return_value = domain
self.mock_enabled_quotas.return_value = ('instances',)
self.mock_get_project_groups_roles.side_effect = \
self.exceptions.keystone
@ -1570,6 +1596,8 @@ class DetailProjectViewTests(test.BaseAdminViewTests):
self.mock_tenant_get.assert_called_once_with(test.IsHttpRequest(),
self.tenant.id)
self.mock_domain_get.assert_called_once_with(test.IsHttpRequest(),
domain.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)

View File

@ -10,7 +10,9 @@
# License for the specific language governing permissions and limitations
# under the License.
import logging
from django.conf import settings
from django.utils.translation import ugettext_lazy as _
from horizon import exceptions
@ -21,6 +23,10 @@ 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
from openstack_dashboard import policy
LOG = logging.getLogger(__name__)
class OverviewTab(tabs.Tab):
@ -32,8 +38,50 @@ class OverviewTab(tabs.Tab):
slug = "overview"
template_name = 'identity/users/_detail_overview.html'
def _get_domain_name(self, user):
domain_name = ''
if api.keystone.VERSIONS.active >= 3:
try:
if policy.check((("identity", "identity:get_domain"),),
self.request):
domain = api.keystone.domain_get(
self.request, user.domain_id)
domain_name = domain.name
else:
domain = api.keystone.get_default_domain(self.request)
domain_name = domain.get('name')
except Exception:
exceptions.handle(self.request,
_('Unable to retrieve user domain.'))
return domain_name
def _get_project_name(self, user):
project_id = user.project_id
if not project_id:
return
try:
tenant = api.keystone.tenant_get(self.request, project_id)
return tenant.name
except Exception as e:
LOG.error('Failed to get tenant %(project_id)s: %(reason)s',
{'project_id': project_id, 'reason': e})
def _get_extras(self, user):
if api.keystone.VERSIONS.active >= 3:
extra_info = getattr(settings, 'USER_TABLE_EXTRA_INFO', {})
return dict((display_key, getattr(user, key, ''))
for key, display_key in extra_info.items())
else:
return {}
def get_context_data(self, request):
return {"user": self.tab_group.kwargs['user']}
user = self.tab_group.kwargs['user']
return {
"user": user,
"domain_name": self._get_domain_name(user),
'extras': self._get_extras(user),
'project_name': self._get_project_name(user),
}
class RoleAssignmentsTab(tabs.TableTab):

View File

@ -2,33 +2,32 @@
<div class="detail">
<dl class="dl-horizontal">
{% if domain_id %}
<dt>{% trans "Domain ID" %}</dt>
<dd>{{ domain_id }}</dd>
{% endif %}
<dt>{% trans "Name" %}</dt>
<dd data-display="{{ user.name|default:user.id }}" class="word-wrap">{{ user.name }}</dd>
<dt>{% trans "ID" %}</dt>
<dd>{{ user.id }}</dd>
{% if domain_name %}
<dt>{% trans "Domain Name" %}</dt>
<dd class="word-wrap">{{ domain_name }}</dd>
{% endif %}
<dt>{% trans "User Name" %}</dt>
<dd data-display="{{ user.name|default:user.id }}" class="word-wrap">{{ user.name }}</dd>
{% if description %}
<dt>{% trans "Description" %}</dt>
<dd>{{ description }}</dd>
{% endif %}
<dt>{% trans "ID" %}</dt>
<dd>{{ user.id }}</dd>
<dt>{% trans "Domain ID" %}</dt>
<dd>{{ user.domain_id }}</dd>
<dt>{% trans "Description" %}</dt>
<dd>{{ user.description|default:_("-") }}</dd>
<dt>{% trans "Email" %}</dt>
<dd>{{ user.email|default:_("None") }}</dd>
<dd>{{ user.email|default:_("-") }}</dd>
<dt>{% trans "Enabled" %}</dt>
<dd>{{ user.enabled|yesno|capfirst }}</dd>
<dt>{% trans "Password Expires At" %}</dt>
<dd>{{ user.password_expires_at }}</dd>
<dt>{% trans "Primary Project ID" %}</dt>
<dd>{{ user.project_id }}</dd>
{% if tenant_name %}
<dt>{% trans "Primary Project Name" %}</dt>
<dd class="word-wrap">{{ tenant_name }}</dd>
<dt>{% trans "Primary Project" %}</dt>
{% if user.project_id %}
<dd class="word-wrap">
<a href="{% url 'horizon:identity:projects:detail' project_id=user.project_id %}">
{{ project_name|default:user.project_id }}</a>
</dd>
{% else %}
<dd>{% trans "-" %}</dd>
{% endif %}
{% if extras %}
{% for key, value in extras.items %}

View File

@ -864,7 +864,7 @@ class UsersViewTests(test.BaseAdminViewTests):
self.assertTemplateUsed(res, 'identity/users/_detail_overview.html')
self.assertEqual(res.context['user'].name, user.name)
self.assertEqual(res.context['user'].id, user.id)
self.assertEqual(res.context['tenant_name'], tenant.name)
self.assertEqual(res.context['project_name'], tenant.name)
self.mock_domain_get.assert_called_once_with(test.IsHttpRequest(), '1')
self.mock_user_get.assert_called_once_with(test.IsHttpRequest(), '1',
@ -914,7 +914,7 @@ class UsersViewTests(test.BaseAdminViewTests):
self.assertTemplateUsed(res, 'identity/users/_detail_overview.html')
self.assertEqual(res.context['user'].name, user.name)
self.assertEqual(res.context['user'].id, user.id)
self.assertEqual(res.context['tenant_name'], tenant.name)
self.assertEqual(res.context['project_name'], tenant.name)
self.mock_domain_get.assert_called_once_with(test.IsHttpRequest(), '1')
self.mock_user_get.assert_called_once_with(test.IsHttpRequest(), '1',

View File

@ -207,48 +207,12 @@ class DetailView(tabs.TabView):
def get_context_data(self, **kwargs):
context = super(DetailView, self).get_context_data(**kwargs)
user = self.get_data()
tenant = self.get_tenant(user.project_id)
table = project_tables.UsersTable(self.request)
domain_id = getattr(user, "domain_id", None)
domain_name = ''
if api.keystone.VERSIONS.active >= 3:
try:
if policy.check((("identity", "identity:get_domain"),),
self.request):
domain = api.keystone.domain_get(
self.request, domain_id)
domain_name = domain.name
else:
domain = api.keystone.get_default_domain(self.request)
domain_name = domain.get('name')
except Exception:
exceptions.handle(self.request,
_('Unable to retrieve project domain.'))
context["description"] = getattr(user, "description", _("None"))
extra_info = getattr(settings, 'USER_TABLE_EXTRA_INFO', {})
context['extras'] = dict(
(display_key, getattr(user, key, ''))
for key, display_key in extra_info.items())
context["user"] = user
if tenant:
context["tenant_name"] = tenant.name
context["domain_id"] = domain_id
context["domain_name"] = domain_name
context["url"] = self.get_redirect_url()
context["actions"] = table.render_row_actions(user)
return context
@memoized.memoized_method
def get_tenant(self, project_id):
tenant = None
if project_id:
try:
tenant = api.keystone.tenant_get(self.request, project_id)
except Exception as e:
LOG.error('Failed to get tenant %(project_id)s: %(reason)s',
{'project_id': project_id, 'reason': e})
return tenant
@memoized.memoized_method
def get_data(self):
try: