Merge "Show domain info in project and user detail panel"

This commit is contained in:
Zuul 2019-02-12 21:54:18 +00:00 committed by Gerrit Code Review
commit 4242987e42
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

@ -204,48 +204,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: