Merge "Separating Identity Dashboard and using RBAC"
This commit is contained in:
commit
6393dbe003
|
@ -61,6 +61,8 @@ class NotRegistered(Exception):
|
|||
|
||||
|
||||
class HorizonComponent(object):
|
||||
policy_rules = None
|
||||
|
||||
def __init__(self):
|
||||
super(HorizonComponent, self).__init__()
|
||||
if not self.slug:
|
||||
|
@ -88,6 +90,29 @@ class HorizonComponent(object):
|
|||
urlpatterns = patterns('')
|
||||
return urlpatterns
|
||||
|
||||
def can_access(self, context):
|
||||
"""Checks to see that the user has role based access to this component.
|
||||
|
||||
This method should be overridden to return the result of
|
||||
any policy checks required for the user to access this component
|
||||
when more complex checks are required.
|
||||
"""
|
||||
return self._can_access(context['request'])
|
||||
|
||||
def _can_access(self, request):
|
||||
policy_check = getattr(settings, "POLICY_CHECK_FUNCTION", None)
|
||||
|
||||
# this check is an OR check rather than an AND check that is the
|
||||
# default in the policy engine, so calling each rule individually
|
||||
if policy_check and self.policy_rules:
|
||||
for rule in self.policy_rules:
|
||||
if policy_check((rule,), request):
|
||||
return True
|
||||
return False
|
||||
|
||||
# default to allowed
|
||||
return True
|
||||
|
||||
|
||||
class Registry(object):
|
||||
def __init__(self):
|
||||
|
@ -543,6 +568,30 @@ class Dashboard(Registry, HorizonComponent):
|
|||
del loaders.panel_template_dirs[key]
|
||||
return success
|
||||
|
||||
def can_access(self, context):
|
||||
"""Checks for role based access for this dashboard.
|
||||
|
||||
Checks for access to any panels in the dashboard and of the the
|
||||
dashboard itself.
|
||||
|
||||
This method should be overridden to return the result of
|
||||
any policy checks required for the user to access this dashboard
|
||||
when more complex checks are required.
|
||||
"""
|
||||
|
||||
# if the dashboard has policy rules, honor those above individual
|
||||
# panels
|
||||
if not self._can_access(context['request']):
|
||||
return False
|
||||
|
||||
# check if access is allowed to a single panel,
|
||||
# the default for each panel is True
|
||||
for panel in self.get_panels():
|
||||
if panel.can_access(context):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
class Workflow(object):
|
||||
def __init__(*args, **kwargs):
|
||||
|
|
|
@ -3,12 +3,16 @@
|
|||
{% for heading, panels in components.iteritems %}
|
||||
{% with panels|has_permissions_on_list:user as filtered_panels %}
|
||||
{% if filtered_panels %}
|
||||
{% if heading %}<h4>{{ heading }}</h4>{% endif %}
|
||||
{% if accessible_panels %}
|
||||
{% if heading %}<h4>{{ heading }}</h4>{% endif %}
|
||||
{% endif %}
|
||||
<ul class="main_nav">
|
||||
{% for panel in filtered_panels %}
|
||||
<li>
|
||||
<a href="{{ panel.get_absolute_url }}" {% if current == panel.slug %}class="active"{% endif %} tabindex='1'>{{ panel.name }}</a>
|
||||
</li>
|
||||
{% if panel in accessible_panels or current == panel.slug %}
|
||||
<li>
|
||||
<a href="{{ panel.get_absolute_url }}" {% if current == panel.slug %}class="active"{% endif %} tabindex='1'>{{ panel.name }}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
|
|
|
@ -53,15 +53,19 @@ def horizon_nav(context):
|
|||
for group in panel_groups.values():
|
||||
allowed_panels = []
|
||||
for panel in group:
|
||||
if callable(panel.nav) and panel.nav(context):
|
||||
if callable(panel.nav) and panel.nav(context) and \
|
||||
panel.can_access(context):
|
||||
allowed_panels.append(panel)
|
||||
elif not callable(panel.nav) and panel.nav:
|
||||
elif not callable(panel.nav) and panel.nav and \
|
||||
panel.can_access(context):
|
||||
allowed_panels.append(panel)
|
||||
if allowed_panels:
|
||||
non_empty_groups.append((group.name, allowed_panels))
|
||||
if callable(dash.nav) and dash.nav(context):
|
||||
if callable(dash.nav) and dash.nav(context) and \
|
||||
dash.can_access(context):
|
||||
dashboards.append((dash, SortedDict(non_empty_groups)))
|
||||
elif not callable(dash.nav) and dash.nav:
|
||||
elif not callable(dash.nav) and dash.nav and \
|
||||
dash.can_access(context):
|
||||
dashboards.append((dash, SortedDict(non_empty_groups)))
|
||||
return {'components': dashboards,
|
||||
'user': context['request'].user,
|
||||
|
@ -78,10 +82,11 @@ def horizon_main_nav(context):
|
|||
current_dashboard = context['request'].horizon.get('dashboard', None)
|
||||
dashboards = []
|
||||
for dash in Horizon.get_dashboards():
|
||||
if callable(dash.nav) and dash.nav(context):
|
||||
dashboards.append(dash)
|
||||
elif dash.nav:
|
||||
dashboards.append(dash)
|
||||
if dash.can_access(context['request']):
|
||||
if callable(dash.nav) and dash.nav(context):
|
||||
dashboards.append(dash)
|
||||
elif dash.nav:
|
||||
dashboards.append(dash)
|
||||
return {'components': dashboards,
|
||||
'user': context['request'].user,
|
||||
'current': current_dashboard,
|
||||
|
@ -100,9 +105,11 @@ def horizon_dashboard_nav(context):
|
|||
for group in panel_groups.values():
|
||||
allowed_panels = []
|
||||
for panel in group:
|
||||
if callable(panel.nav) and panel.nav(context):
|
||||
if callable(panel.nav) and panel.nav(context) and \
|
||||
panel.can_access(context):
|
||||
allowed_panels.append(panel)
|
||||
elif not callable(panel.nav) and panel.nav:
|
||||
elif not callable(panel.nav) and panel.nav and \
|
||||
panel.can_access(context):
|
||||
allowed_panels.append(panel)
|
||||
if allowed_panels:
|
||||
non_empty_groups.append((group.name, allowed_panels))
|
||||
|
|
|
@ -53,6 +53,19 @@ class AdminPanel(horizon.Panel):
|
|||
urls = 'horizon.test.test_dashboards.cats.kittens.urls'
|
||||
|
||||
|
||||
class RbacNoAccessPanel(horizon.Panel):
|
||||
name = "RBAC Panel No"
|
||||
slug = "rbac_panel_no"
|
||||
|
||||
def _can_access(self, request):
|
||||
return False
|
||||
|
||||
|
||||
class RbacYesAccessPanel(horizon.Panel):
|
||||
name = "RBAC Panel Yes"
|
||||
slug = "rbac_panel_yes"
|
||||
|
||||
|
||||
class BaseHorizonTests(test.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
|
@ -439,3 +452,67 @@ class CustomPermissionsTests(BaseHorizonTests):
|
|||
follow=False,
|
||||
HTTP_X_REQUESTED_WITH='XMLHttpRequest')
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
|
||||
|
||||
class RbacHorizonTests(test.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(RbacHorizonTests, self).setUp()
|
||||
# Adjust our horizon config and register our custom dashboards/panels.
|
||||
self.old_default_dash = settings.HORIZON_CONFIG['default_dashboard']
|
||||
settings.HORIZON_CONFIG['default_dashboard'] = 'cats'
|
||||
self.old_dashboards = settings.HORIZON_CONFIG['dashboards']
|
||||
settings.HORIZON_CONFIG['dashboards'] = ('cats', 'dogs')
|
||||
base.Horizon.register(Cats)
|
||||
base.Horizon.register(Dogs)
|
||||
Cats.register(RbacNoAccessPanel)
|
||||
Cats.default_panel = 'rbac_panel_no'
|
||||
Dogs.register(RbacYesAccessPanel)
|
||||
Dogs.default_panel = 'rbac_panel_yes'
|
||||
# Trigger discovery, registration, and URLconf generation if it
|
||||
# hasn't happened yet.
|
||||
base.Horizon._urls()
|
||||
# Store our original dashboards
|
||||
self._discovered_dashboards = base.Horizon._registry.keys()
|
||||
# Gather up and store our original panels for each dashboard
|
||||
self._discovered_panels = {}
|
||||
for dash in self._discovered_dashboards:
|
||||
panels = base.Horizon._registry[dash]._registry.keys()
|
||||
self._discovered_panels[dash] = panels
|
||||
|
||||
def tearDown(self):
|
||||
super(RbacHorizonTests, self).tearDown()
|
||||
# Restore our settings
|
||||
settings.HORIZON_CONFIG['default_dashboard'] = self.old_default_dash
|
||||
settings.HORIZON_CONFIG['dashboards'] = self.old_dashboards
|
||||
# Destroy our singleton and re-create it.
|
||||
base.HorizonSite._instance = None
|
||||
del base.Horizon
|
||||
base.Horizon = base.HorizonSite()
|
||||
# Reload the convenience references to Horizon stored in __init__
|
||||
reload(import_module("horizon"))
|
||||
# Re-register our original dashboards and panels.
|
||||
# This is necessary because autodiscovery only works on the first
|
||||
# import, and calling reload introduces innumerable additional
|
||||
# problems. Manual re-registration is the only good way for testing.
|
||||
self._discovered_dashboards.remove(Cats)
|
||||
self._discovered_dashboards.remove(Dogs)
|
||||
for dash in self._discovered_dashboards:
|
||||
base.Horizon.register(dash)
|
||||
for panel in self._discovered_panels[dash]:
|
||||
dash.register(panel)
|
||||
|
||||
def test_rbac_panels(self):
|
||||
context = {'request': None}
|
||||
cats = horizon.get_dashboard("cats")
|
||||
self.assertEqual(cats._registered_with, base.Horizon)
|
||||
self.assertQuerysetEqual(cats.get_panels(),
|
||||
['<Panel: rbac_panel_no>'])
|
||||
self.assertFalse(cats.can_access(context))
|
||||
|
||||
dogs = horizon.get_dashboard("dogs")
|
||||
self.assertEqual(dogs._registered_with, base.Horizon)
|
||||
self.assertQuerysetEqual(dogs.get_panels(),
|
||||
['<Panel: rbac_panel_yes>'])
|
||||
|
||||
self.assertTrue(dogs.can_access(context))
|
||||
|
|
|
@ -252,8 +252,9 @@ def tenant_delete(request, project):
|
|||
return manager.delete(project)
|
||||
|
||||
|
||||
def tenant_list(request, paginate=False, marker=None, domain=None, user=None):
|
||||
manager = VERSIONS.get_project_manager(request, admin=True)
|
||||
def tenant_list(request, paginate=False, marker=None, domain=None, user=None,
|
||||
admin=True):
|
||||
manager = VERSIONS.get_project_manager(request, admin=admin)
|
||||
page_size = utils.get_page_size(request)
|
||||
|
||||
limit = None
|
||||
|
|
|
@ -25,16 +25,10 @@ class SystemPanels(horizon.PanelGroup):
|
|||
'networks', 'routers', 'info')
|
||||
|
||||
|
||||
class IdentityPanels(horizon.PanelGroup):
|
||||
slug = "identity"
|
||||
name = _("Identity")
|
||||
panels = ('domains', 'projects', 'users', 'groups', 'roles')
|
||||
|
||||
|
||||
class Admin(horizon.Dashboard):
|
||||
name = _("Admin")
|
||||
slug = "admin"
|
||||
panels = (SystemPanels, IdentityPanels)
|
||||
panels = (SystemPanels,)
|
||||
default_panel = 'overview'
|
||||
permissions = ('openstack.roles.admin',)
|
||||
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
# 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.
|
||||
|
||||
GROUPS_INDEX_URL = 'horizon:admin:groups:index'
|
||||
GROUPS_INDEX_VIEW_TEMPLATE = 'admin/groups/index.html'
|
||||
GROUPS_CREATE_URL = 'horizon:admin:groups:create'
|
||||
GROUPS_CREATE_VIEW_TEMPLATE = 'admin/groups/create.html'
|
||||
GROUPS_UPDATE_URL = 'horizon:admin:groups:update'
|
||||
GROUPS_UPDATE_VIEW_TEMPLATE = 'admin/groups/update.html'
|
||||
GROUPS_MANAGE_URL = 'horizon:admin:groups:manage_members'
|
||||
GROUPS_MANAGE_VIEW_TEMPLATE = 'admin/groups/manage.html'
|
||||
GROUPS_ADD_MEMBER_URL = 'horizon:admin:groups:add_members'
|
||||
GROUPS_ADD_MEMBER_VIEW_TEMPLATE = 'admin/groups/add_non_member.html'
|
||||
GROUPS_ADD_MEMBER_AJAX_VIEW_TEMPLATE = 'admin/groups/_add_non_member.html'
|
|
@ -0,0 +1,28 @@
|
|||
# Copyright 2014 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# 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 _
|
||||
|
||||
import horizon
|
||||
|
||||
|
||||
class Identity(horizon.Dashboard):
|
||||
name = _("Identity")
|
||||
slug = "identity"
|
||||
default_panel = 'projects'
|
||||
panels = ('domains', 'projects', 'users', 'groups', 'roles',)
|
||||
|
||||
|
||||
horizon.register(Identity)
|
|
@ -15,8 +15,8 @@
|
|||
DOMAIN_INFO_FIELDS = ("name",
|
||||
"description",
|
||||
"enabled")
|
||||
DOMAINS_INDEX_URL = 'horizon:admin:domains:index'
|
||||
DOMAINS_INDEX_VIEW_TEMPLATE = 'admin/domains/index.html'
|
||||
DOMAINS_CREATE_URL = 'horizon:admin:domains:create'
|
||||
DOMAINS_UPDATE_URL = 'horizon:admin:domains:update'
|
||||
DOMAINS_INDEX_URL = 'horizon:identity:domains:index'
|
||||
DOMAINS_INDEX_VIEW_TEMPLATE = 'identity/domains/index.html'
|
||||
DOMAINS_CREATE_URL = 'horizon:identity:domains:create'
|
||||
DOMAINS_UPDATE_URL = 'horizon:identity:domains:update'
|
||||
DOMAIN_GROUP_MEMBER_SLUG = "update_group_members"
|
|
@ -17,13 +17,15 @@ from django.utils.translation import ugettext_lazy as _
|
|||
import horizon
|
||||
|
||||
from openstack_dashboard.api import keystone
|
||||
from openstack_dashboard.dashboards.admin import dashboard
|
||||
from openstack_dashboard.dashboards.identity import dashboard
|
||||
|
||||
|
||||
class Domains(horizon.Panel):
|
||||
name = _("Domains")
|
||||
slug = 'domains'
|
||||
policy_rules = (("identity", "identity:get_domain"),
|
||||
("identity", "identity:list_domains"))
|
||||
|
||||
|
||||
if keystone.VERSIONS.active >= 3:
|
||||
dashboard.Admin.register(Domains)
|
||||
dashboard.Identity.register(Domains)
|
|
@ -26,7 +26,7 @@ from horizon import tables
|
|||
|
||||
from openstack_dashboard import api
|
||||
|
||||
from openstack_dashboard.dashboards.admin.domains import constants
|
||||
from openstack_dashboard.dashboards.identity.domains import constants
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
@ -35,7 +35,7 @@ LOG = logging.getLogger(__name__)
|
|||
class ViewGroupsLink(tables.LinkAction):
|
||||
name = "groups"
|
||||
verbose_name = _("Modify Groups")
|
||||
url = "horizon:admin:domains:update"
|
||||
url = "horizon:identity:domains:update"
|
||||
classes = ("ajax-modal",)
|
||||
icon = "pencil"
|
||||
|
|
@ -24,8 +24,8 @@ from horizon.workflows import views
|
|||
from openstack_dashboard import api
|
||||
from openstack_dashboard.test import helpers as test
|
||||
|
||||
from openstack_dashboard.dashboards.admin.domains import constants
|
||||
from openstack_dashboard.dashboards.admin.domains import workflows
|
||||
from openstack_dashboard.dashboards.identity.domains import constants
|
||||
from openstack_dashboard.dashboards.identity.domains import workflows
|
||||
|
||||
|
||||
DOMAINS_INDEX_URL = reverse(constants.DOMAINS_INDEX_URL)
|
||||
|
@ -134,7 +134,7 @@ class CreateDomainWorkflowTests(test.BaseAdminViewTests):
|
|||
return domain_info
|
||||
|
||||
def test_add_domain_get(self):
|
||||
url = reverse('horizon:admin:domains:create')
|
||||
url = reverse('horizon:identity:domains:create')
|
||||
res = self.client.get(url)
|
||||
|
||||
self.assertTemplateUsed(res, views.WorkflowView.template_name)
|
|
@ -15,7 +15,7 @@
|
|||
from django.conf.urls import patterns # noqa
|
||||
from django.conf.urls import url # noqa
|
||||
|
||||
from openstack_dashboard.dashboards.admin.domains import views
|
||||
from openstack_dashboard.dashboards.identity.domains import views
|
||||
|
||||
|
||||
urlpatterns = patterns('',
|
|
@ -16,15 +16,17 @@ from django.core.urlresolvers import reverse
|
|||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from horizon import exceptions
|
||||
from horizon import messages
|
||||
from horizon import tables
|
||||
from horizon import workflows
|
||||
|
||||
from openstack_dashboard import api
|
||||
from openstack_dashboard import policy
|
||||
|
||||
from openstack_dashboard.dashboards.admin.domains import constants
|
||||
from openstack_dashboard.dashboards.admin.domains \
|
||||
from openstack_dashboard.dashboards.identity.domains import constants
|
||||
from openstack_dashboard.dashboards.identity.domains \
|
||||
import tables as project_tables
|
||||
from openstack_dashboard.dashboards.admin.domains \
|
||||
from openstack_dashboard.dashboards.identity.domains \
|
||||
import workflows as project_workflows
|
||||
|
||||
|
||||
|
@ -35,16 +37,30 @@ class IndexView(tables.DataTableView):
|
|||
def get_data(self):
|
||||
domains = []
|
||||
domain_context = self.request.session.get('domain_context', None)
|
||||
try:
|
||||
if domain_context:
|
||||
if policy.check((("identity", "identity:list_domains"),),
|
||||
self.request):
|
||||
try:
|
||||
if domain_context:
|
||||
domain = api.keystone.domain_get(self.request,
|
||||
domain_context)
|
||||
domains.append(domain)
|
||||
else:
|
||||
domains = api.keystone.domain_list(self.request)
|
||||
except Exception:
|
||||
exceptions.handle(self.request,
|
||||
_('Unable to retrieve domain list.'))
|
||||
elif policy.check((("identity", "identity:get_domain"),),
|
||||
self.request):
|
||||
try:
|
||||
domain = api.keystone.domain_get(self.request,
|
||||
domain_context)
|
||||
self.request.user.domain_id)
|
||||
domains.append(domain)
|
||||
else:
|
||||
domains = api.keystone.domain_list(self.request)
|
||||
except Exception:
|
||||
exceptions.handle(self.request,
|
||||
_('Unable to retrieve domain list.'))
|
||||
except Exception:
|
||||
exceptions.handle(self.request,
|
||||
_('Unable to retrieve domain information.'))
|
||||
else:
|
||||
msg = _("Insufficient privilege level to view domain information.")
|
||||
messages.info(self.request, msg)
|
||||
return domains
|
||||
|
||||
|
|
@ -24,7 +24,7 @@ from horizon import workflows
|
|||
|
||||
from openstack_dashboard import api
|
||||
|
||||
from openstack_dashboard.dashboards.admin.domains import constants
|
||||
from openstack_dashboard.dashboards.identity.domains import constants
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
|
@ -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.
|
||||
|
||||
GROUPS_INDEX_URL = 'horizon:identity:groups:index'
|
||||
GROUPS_INDEX_VIEW_TEMPLATE = 'identity/groups/index.html'
|
||||
GROUPS_CREATE_URL = 'horizon:identity:groups:create'
|
||||
GROUPS_CREATE_VIEW_TEMPLATE = 'identity/groups/create.html'
|
||||
GROUPS_UPDATE_URL = 'horizon:identity:groups:update'
|
||||
GROUPS_UPDATE_VIEW_TEMPLATE = 'identity/groups/update.html'
|
||||
GROUPS_MANAGE_URL = 'horizon:identity:groups:manage_members'
|
||||
GROUPS_MANAGE_VIEW_TEMPLATE = 'identity/groups/manage.html'
|
||||
GROUPS_ADD_MEMBER_URL = 'horizon:identity:groups:add_members'
|
||||
GROUPS_ADD_MEMBER_VIEW_TEMPLATE = 'identity/groups/add_non_member.html'
|
||||
GROUPS_ADD_MEMBER_AJAX_VIEW_TEMPLATE = 'identity/groups/_add_non_member.html'
|
|
@ -17,13 +17,14 @@ from django.utils.translation import ugettext_lazy as _
|
|||
import horizon
|
||||
|
||||
from openstack_dashboard.api import keystone
|
||||
from openstack_dashboard.dashboards.admin import dashboard
|
||||
from openstack_dashboard.dashboards.identity import dashboard
|
||||
|
||||
|
||||
class Groups(horizon.Panel):
|
||||
name = _("Groups")
|
||||
slug = 'groups'
|
||||
policy_rules = (("identity", "identity:list_groups"),)
|
||||
|
||||
|
||||
if keystone.VERSIONS.active >= 3:
|
||||
dashboard.Admin.register(Groups)
|
||||
dashboard.Identity.register(Groups)
|
|
@ -22,7 +22,7 @@ from horizon import tables
|
|||
|
||||
from openstack_dashboard import api
|
||||
|
||||
from openstack_dashboard.dashboards.admin.groups import constants
|
||||
from openstack_dashboard.dashboards.identity.groups import constants
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
|
@ -5,5 +5,5 @@
|
|||
{% block modal-header %}{% trans "Add Group Assignment" %}{% endblock %}
|
||||
|
||||
{% block modal-footer %}
|
||||
<a href="{% url 'horizon:admin:groups:manage_members' group.id %}" class="btn btn-default secondary cancel close">{% trans "Cancel" %}</a>
|
||||
<a href="{% url 'horizon:identity:groups:manage_members' group.id %}" class="btn btn-default secondary cancel close">{% trans "Cancel" %}</a>
|
||||
{% endblock %}
|
|
@ -3,7 +3,7 @@
|
|||
{% load url from future %}
|
||||
|
||||
{% block form_id %}create_group_form{% endblock %}
|
||||
{% block form_action %}{% url 'horizon:admin:groups:create' %}{% endblock %}
|
||||
{% block form_action %}{% url 'horizon:identity:groups:create' %}{% endblock %}
|
||||
|
||||
{% block modal-header %}{% trans "Create Group" %}{% endblock %}
|
||||
|
||||
|
@ -21,5 +21,5 @@
|
|||
|
||||
{% block modal-footer %}
|
||||
<input class="btn btn-primary pull-right" type="submit" value="{% trans "Create Group" %}" />
|
||||
<a href="{% url 'horizon:admin:groups:index' %}" class="btn btn-default secondary cancel close">{% trans "Cancel" %}</a>
|
||||
<a href="{% url 'horizon:identity:groups:index' %}" class="btn btn-default secondary cancel close">{% trans "Cancel" %}</a>
|
||||
{% endblock %}
|
|
@ -3,7 +3,7 @@
|
|||
{% load url from future %}
|
||||
|
||||
{% block form_id %}update_group_form{% endblock %}
|
||||
{% block form_action %}{% url 'horizon:admin:groups:update' group.id %}{% endblock %}
|
||||
{% block form_action %}{% url 'horizon:identity:groups:update' group.id %}{% endblock %}
|
||||
|
||||
{% block modal-header %}{% trans "Update Group" %}{% endblock %}
|
||||
|
||||
|
@ -21,5 +21,5 @@
|
|||
|
||||
{% block modal-footer %}
|
||||
<input class="btn btn-primary pull-right" type="submit" value="{% trans "Update Group" %}" />
|
||||
<a href="{% url 'horizon:admin:groups:index' %}" class="btn btn-default secondary cancel close">{% trans "Cancel" %}</a>
|
||||
<a href="{% url 'horizon:identity:groups:index' %}" class="btn btn-default secondary cancel close">{% trans "Cancel" %}</a>
|
||||
{% endblock %}
|
|
@ -3,5 +3,5 @@
|
|||
{% block title %}{% trans 'Add User to Group' %}{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
{% include 'admin/groups/_add_non_member.html' %}
|
||||
{% include 'identity/groups/_add_non_member.html' %}
|
||||
{% endblock %}
|
|
@ -7,5 +7,5 @@
|
|||
{% endblock page_header %}
|
||||
|
||||
{% block main %}
|
||||
{% include 'admin/groups/_create.html' %}
|
||||
{% include 'identity/groups/_create.html' %}
|
||||
{% endblock %}
|
|
@ -7,5 +7,5 @@
|
|||
{% endblock page_header %}
|
||||
|
||||
{% block main %}
|
||||
{% include 'admin/groups/_update.html' %}
|
||||
{% include 'identity/groups/_update.html' %}
|
||||
{% endblock %}
|
|
@ -21,7 +21,7 @@ from mox import IsA # noqa
|
|||
from openstack_dashboard import api
|
||||
from openstack_dashboard.test import helpers as test
|
||||
|
||||
from openstack_dashboard.dashboards.admin.groups import constants
|
||||
from openstack_dashboard.dashboards.identity.groups import constants
|
||||
|
||||
|
||||
GROUPS_INDEX_URL = reverse(constants.GROUPS_INDEX_URL)
|
|
@ -15,7 +15,7 @@
|
|||
from django.conf.urls import patterns # noqa
|
||||
from django.conf.urls import url # noqa
|
||||
|
||||
from openstack_dashboard.dashboards.admin.groups import views
|
||||
from openstack_dashboard.dashboards.identity.groups import views
|
||||
|
||||
|
||||
urlpatterns = patterns('',
|
|
@ -18,15 +18,17 @@ from django.utils.translation import ugettext_lazy as _
|
|||
|
||||
from horizon import exceptions
|
||||
from horizon import forms
|
||||
from horizon import messages
|
||||
from horizon import tables
|
||||
from horizon.utils import memoized
|
||||
|
||||
from openstack_dashboard import api
|
||||
from openstack_dashboard import policy
|
||||
|
||||
from openstack_dashboard.dashboards.admin.groups import constants
|
||||
from openstack_dashboard.dashboards.admin.groups \
|
||||
from openstack_dashboard.dashboards.identity.groups import constants
|
||||
from openstack_dashboard.dashboards.identity.groups \
|
||||
import forms as project_forms
|
||||
from openstack_dashboard.dashboards.admin.groups \
|
||||
from openstack_dashboard.dashboards.identity.groups \
|
||||
import tables as project_tables
|
||||
|
||||
|
||||
|
@ -37,12 +39,17 @@ class IndexView(tables.DataTableView):
|
|||
def get_data(self):
|
||||
groups = []
|
||||
domain_context = self.request.session.get('domain_context', None)
|
||||
try:
|
||||
groups = api.keystone.group_list(self.request,
|
||||
domain=domain_context)
|
||||
except Exception:
|
||||
exceptions.handle(self.request,
|
||||
_('Unable to retrieve group list.'))
|
||||
if policy.check((("identity", "identity:list_groups"),),
|
||||
self.request):
|
||||
try:
|
||||
groups = api.keystone.group_list(self.request,
|
||||
domain=domain_context)
|
||||
except Exception:
|
||||
exceptions.handle(self.request,
|
||||
_('Unable to retrieve group list.'))
|
||||
else:
|
||||
msg = _("Insufficient privilege level to view group information.")
|
||||
messages.info(self.request, msg)
|
||||
return groups
|
||||
|
||||
|
|
@ -20,12 +20,14 @@ from django.utils.translation import ugettext_lazy as _
|
|||
|
||||
import horizon
|
||||
|
||||
from openstack_dashboard.dashboards.admin import dashboard
|
||||
from openstack_dashboard.dashboards.identity import dashboard
|
||||
|
||||
|
||||
class Tenants(horizon.Panel):
|
||||
name = _("Projects")
|
||||
slug = 'projects'
|
||||
policy_rules = (("identity", "identity:list_projects"),
|
||||
("identity", "identity:list_user_projects"))
|
||||
|
||||
|
||||
dashboard.Admin.register(Tenants)
|
||||
dashboard.Identity.register(Tenants)
|
|
@ -21,13 +21,13 @@ from horizon import tables
|
|||
from keystoneclient.exceptions import Conflict # noqa
|
||||
|
||||
from openstack_dashboard import api
|
||||
from openstack_dashboard.api import keystone
|
||||
from openstack_dashboard import policy
|
||||
|
||||
|
||||
class ViewMembersLink(tables.LinkAction):
|
||||
name = "users"
|
||||
verbose_name = _("Modify Users")
|
||||
url = "horizon:admin:projects:update"
|
||||
url = "horizon:identity:projects:update"
|
||||
classes = ("ajax-modal",)
|
||||
icon = "pencil"
|
||||
policy_rules = (("identity", "identity:list_users"),
|
||||
|
@ -43,12 +43,13 @@ class ViewMembersLink(tables.LinkAction):
|
|||
class ViewGroupsLink(tables.LinkAction):
|
||||
name = "groups"
|
||||
verbose_name = _("Modify Groups")
|
||||
url = "horizon:admin:projects:update"
|
||||
url = "horizon:identity:projects:update"
|
||||
classes = ("ajax-modal",)
|
||||
icon = "pencil"
|
||||
policy_rules = (("identity", "identity:list_groups"),)
|
||||
|
||||
def allowed(self, request, project):
|
||||
return keystone.VERSIONS.active >= 3
|
||||
return api.keystone.VERSIONS.active >= 3
|
||||
|
||||
def get_link_url(self, project):
|
||||
step = 'update_group_members'
|
||||
|
@ -60,15 +61,18 @@ class ViewGroupsLink(tables.LinkAction):
|
|||
class UsageLink(tables.LinkAction):
|
||||
name = "usage"
|
||||
verbose_name = _("View Usage")
|
||||
url = "horizon:admin:projects:usage"
|
||||
url = "horizon:identity:projects:usage"
|
||||
icon = "stats"
|
||||
policy_rules = (("compute", "compute_extension:simple_tenant_usage:show"),)
|
||||
|
||||
def allowed(self, request, project):
|
||||
return request.user.is_superuser
|
||||
|
||||
|
||||
class CreateProject(tables.LinkAction):
|
||||
name = "create"
|
||||
verbose_name = _("Create Project")
|
||||
url = "horizon:admin:projects:create"
|
||||
url = "horizon:identity:projects:create"
|
||||
classes = ("ajax-modal",)
|
||||
icon = "plus"
|
||||
policy_rules = (('identity', 'identity:create_project'),)
|
||||
|
@ -80,7 +84,7 @@ class CreateProject(tables.LinkAction):
|
|||
class UpdateProject(tables.LinkAction):
|
||||
name = "update"
|
||||
verbose_name = _("Edit Project")
|
||||
url = "horizon:admin:projects:update"
|
||||
url = "horizon:identity:projects:update"
|
||||
classes = ("ajax-modal",)
|
||||
icon = "pencil"
|
||||
policy_rules = (('identity', 'identity:update_project'),)
|
||||
|
@ -92,7 +96,7 @@ class UpdateProject(tables.LinkAction):
|
|||
class ModifyQuotas(tables.LinkAction):
|
||||
name = "quotas"
|
||||
verbose_name = _("Modify Quotas")
|
||||
url = "horizon:admin:projects:update"
|
||||
url = "horizon:identity:projects:update"
|
||||
classes = ("ajax-modal",)
|
||||
icon = "pencil"
|
||||
policy_rules = (('compute', "compute_extension:quotas:update"),)
|
||||
|
@ -141,7 +145,9 @@ class UpdateRow(tables.Row):
|
|||
|
||||
class UpdateCell(tables.UpdateAction):
|
||||
def allowed(self, request, project, cell):
|
||||
return api.keystone.keystone_can_edit_project()
|
||||
return api.keystone.keystone_can_edit_project() and \
|
||||
policy.check((("identity", "identity:update_project"),),
|
||||
request)
|
||||
|
||||
def update_cell(self, request, datum, project_id,
|
||||
cell_name, new_cell_value):
|
|
@ -31,7 +31,7 @@ from horizon import exceptions
|
|||
from horizon.workflows import views
|
||||
|
||||
from openstack_dashboard import api
|
||||
from openstack_dashboard.dashboards.admin.projects import workflows
|
||||
from openstack_dashboard.dashboards.identity.projects import workflows
|
||||
from openstack_dashboard.test import helpers as test
|
||||
from openstack_dashboard import usage
|
||||
from openstack_dashboard.usage import quotas
|
||||
|
@ -44,22 +44,23 @@ if with_sel:
|
|||
from socket import timeout as socket_timeout # noqa
|
||||
|
||||
|
||||
INDEX_URL = reverse('horizon:admin:projects:index')
|
||||
INDEX_URL = reverse('horizon:identity:projects:index')
|
||||
USER_ROLE_PREFIX = workflows.PROJECT_GROUP_MEMBER_SLUG + "_role_"
|
||||
GROUP_ROLE_PREFIX = workflows.PROJECT_USER_MEMBER_SLUG + "_role_"
|
||||
|
||||
|
||||
@test.create_stubs({api.keystone: ('tenant_list',)})
|
||||
class TenantsViewTests(test.BaseAdminViewTests):
|
||||
@test.create_stubs({api.keystone: ('tenant_list',)})
|
||||
def test_index(self):
|
||||
api.keystone.tenant_list(IsA(http.HttpRequest),
|
||||
domain=None,
|
||||
paginate=True) \
|
||||
paginate=True,
|
||||
marker=None) \
|
||||
.AndReturn([self.tenants.list(), False])
|
||||
self.mox.ReplayAll()
|
||||
|
||||
res = self.client.get(INDEX_URL)
|
||||
self.assertTemplateUsed(res, 'admin/projects/index.html')
|
||||
self.assertTemplateUsed(res, 'identity/projects/index.html')
|
||||
self.assertItemsEqual(res.context['table'].data, self.tenants.list())
|
||||
|
||||
@test.create_stubs({api.keystone: ('tenant_list', )})
|
||||
|
@ -70,16 +71,34 @@ class TenantsViewTests(test.BaseAdminViewTests):
|
|||
domain_tenants = [tenant for tenant in self.tenants.list()
|
||||
if tenant.domain_id == domain.id]
|
||||
api.keystone.tenant_list(IsA(http.HttpRequest),
|
||||
domain=domain.id) \
|
||||
.AndReturn(domain_tenants)
|
||||
domain=domain.id,
|
||||
paginate=True,
|
||||
marker=None) \
|
||||
.AndReturn([domain_tenants, False])
|
||||
self.mox.ReplayAll()
|
||||
|
||||
res = self.client.get(INDEX_URL)
|
||||
self.assertTemplateUsed(res, 'admin/projects/index.html')
|
||||
self.assertTemplateUsed(res, 'identity/projects/index.html')
|
||||
self.assertItemsEqual(res.context['table'].data, domain_tenants)
|
||||
self.assertContains(res, "<em>test_domain:</em>")
|
||||
|
||||
|
||||
class ProjectsViewNonAdminTests(test.TestCase):
|
||||
@test.create_stubs({api.keystone: ('tenant_list',)})
|
||||
def test_index(self):
|
||||
api.keystone.tenant_list(IsA(http.HttpRequest),
|
||||
user=self.user.id,
|
||||
paginate=True,
|
||||
marker=None,
|
||||
admin=False) \
|
||||
.AndReturn([self.tenants.list(), False])
|
||||
self.mox.ReplayAll()
|
||||
|
||||
res = self.client.get(INDEX_URL)
|
||||
self.assertTemplateUsed(res, 'identity/projects/index.html')
|
||||
self.assertItemsEqual(res.context['table'].data, self.tenants.list())
|
||||
|
||||
|
||||
class CreateProjectWorkflowTests(test.BaseAdminViewTests):
|
||||
def _get_project_info(self, project):
|
||||
domain = self._get_default_domain()
|
||||
|
@ -179,7 +198,7 @@ class CreateProjectWorkflowTests(test.BaseAdminViewTests):
|
|||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
url = reverse('horizon:admin:projects:create')
|
||||
url = reverse('horizon:identity:projects:create')
|
||||
res = self.client.get(url)
|
||||
|
||||
self.assertTemplateUsed(res, views.WorkflowView.template_name)
|
||||
|
@ -240,7 +259,7 @@ class CreateProjectWorkflowTests(test.BaseAdminViewTests):
|
|||
.AndReturn(self.roles.list())
|
||||
self.mox.ReplayAll()
|
||||
|
||||
res = self.client.get(reverse('horizon:admin:projects:create'))
|
||||
res = self.client.get(reverse('horizon:identity:projects:create'))
|
||||
|
||||
self.assertTemplateUsed(res, views.WorkflowView.template_name)
|
||||
if django.VERSION >= (1, 6):
|
||||
|
@ -343,7 +362,7 @@ class CreateProjectWorkflowTests(test.BaseAdminViewTests):
|
|||
|
||||
workflow_data.update(self._get_workflow_data(project, quota))
|
||||
|
||||
url = reverse('horizon:admin:projects:create')
|
||||
url = reverse('horizon:identity:projects:create')
|
||||
res = self.client.post(url, workflow_data)
|
||||
|
||||
self.assertNoFormErrors(res)
|
||||
|
@ -406,7 +425,7 @@ class CreateProjectWorkflowTests(test.BaseAdminViewTests):
|
|||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
url = reverse('horizon:admin:projects:create')
|
||||
url = reverse('horizon:identity:projects:create')
|
||||
res = self.client.get(url)
|
||||
|
||||
self.assertTemplateUsed(res, views.WorkflowView.template_name)
|
||||
|
@ -462,7 +481,7 @@ class CreateProjectWorkflowTests(test.BaseAdminViewTests):
|
|||
|
||||
workflow_data = self._get_workflow_data(project, quota)
|
||||
|
||||
url = reverse('horizon:admin:projects:create')
|
||||
url = reverse('horizon:identity:projects:create')
|
||||
res = self.client.post(url, workflow_data)
|
||||
|
||||
self.assertNoFormErrors(res)
|
||||
|
@ -546,7 +565,7 @@ class CreateProjectWorkflowTests(test.BaseAdminViewTests):
|
|||
|
||||
workflow_data.update(self._get_workflow_data(project, quota))
|
||||
|
||||
url = reverse('horizon:admin:projects:create')
|
||||
url = reverse('horizon:identity:projects:create')
|
||||
res = self.client.post(url, workflow_data)
|
||||
|
||||
self.assertNoFormErrors(res)
|
||||
|
@ -631,7 +650,7 @@ class CreateProjectWorkflowTests(test.BaseAdminViewTests):
|
|||
|
||||
workflow_data.update(self._get_workflow_data(project, quota))
|
||||
|
||||
url = reverse('horizon:admin:projects:create')
|
||||
url = reverse('horizon:identity:projects:create')
|
||||
res = self.client.post(url, workflow_data)
|
||||
|
||||
self.assertNoFormErrors(res)
|
||||
|
@ -681,7 +700,7 @@ class CreateProjectWorkflowTests(test.BaseAdminViewTests):
|
|||
workflow_data = self._get_workflow_data(project, quota)
|
||||
workflow_data["name"] = ""
|
||||
|
||||
url = reverse('horizon:admin:projects:create')
|
||||
url = reverse('horizon:identity:projects:create')
|
||||
res = self.client.post(url, workflow_data)
|
||||
|
||||
self.assertContains(res, "field is required")
|
||||
|
@ -796,7 +815,7 @@ class UpdateProjectWorkflowTests(test.BaseAdminViewTests):
|
|||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
url = reverse('horizon:admin:projects:update',
|
||||
url = reverse('horizon:identity:projects:update',
|
||||
args=[self.tenant.id])
|
||||
res = self.client.get(url)
|
||||
|
||||
|
@ -1028,7 +1047,7 @@ class UpdateProjectWorkflowTests(test.BaseAdminViewTests):
|
|||
"enabled": project.enabled}
|
||||
workflow_data.update(project_data)
|
||||
workflow_data.update(updated_quota)
|
||||
url = reverse('horizon:admin:projects:update',
|
||||
url = reverse('horizon:identity:projects:update',
|
||||
args=[self.tenant.id])
|
||||
res = self.client.post(url, workflow_data)
|
||||
|
||||
|
@ -1064,7 +1083,7 @@ class UpdateProjectWorkflowTests(test.BaseAdminViewTests):
|
|||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
url = reverse('horizon:admin:projects:update',
|
||||
url = reverse('horizon:identity:projects:update',
|
||||
args=[self.tenant.id])
|
||||
res = self.client.get(url)
|
||||
|
||||
|
@ -1180,7 +1199,7 @@ class UpdateProjectWorkflowTests(test.BaseAdminViewTests):
|
|||
"enabled": project.enabled}
|
||||
workflow_data.update(project_data)
|
||||
workflow_data.update(updated_quota)
|
||||
url = reverse('horizon:admin:projects:update',
|
||||
url = reverse('horizon:identity:projects:update',
|
||||
args=[self.tenant.id])
|
||||
res = self.client.post(url, workflow_data)
|
||||
|
||||
|
@ -1354,7 +1373,7 @@ class UpdateProjectWorkflowTests(test.BaseAdminViewTests):
|
|||
"enabled": project.enabled}
|
||||
workflow_data.update(project_data)
|
||||
workflow_data.update(updated_quota)
|
||||
url = reverse('horizon:admin:projects:update',
|
||||
url = reverse('horizon:identity:projects:update',
|
||||
args=[self.tenant.id])
|
||||
res = self.client.post(url, workflow_data)
|
||||
|
||||
|
@ -1488,7 +1507,7 @@ class UpdateProjectWorkflowTests(test.BaseAdminViewTests):
|
|||
"enabled": project.enabled}
|
||||
workflow_data.update(project_data)
|
||||
workflow_data.update(updated_quota)
|
||||
url = reverse('horizon:admin:projects:update',
|
||||
url = reverse('horizon:identity:projects:update',
|
||||
args=[self.tenant.id])
|
||||
res = self.client.post(url, workflow_data)
|
||||
|
||||
|
@ -1520,7 +1539,7 @@ class UpdateProjectWorkflowTests(test.BaseAdminViewTests):
|
|||
.AndReturn(quota)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
url = reverse('horizon:admin:projects:update',
|
||||
url = reverse('horizon:identity:projects:update',
|
||||
args=[self.tenant.id])
|
||||
|
||||
try:
|
||||
|
@ -1586,7 +1605,7 @@ class UsageViewTests(test.BaseAdminViewTests):
|
|||
self.mox.ReplayAll()
|
||||
|
||||
project_id = self.tenants.first().id
|
||||
csv_url = reverse('horizon:admin:projects:usage',
|
||||
csv_url = reverse('horizon:identity:projects:usage',
|
||||
args=[project_id]) + "?format=csv"
|
||||
res = self.client.get(csv_url)
|
||||
self.assertTemplateUsed(res, 'project/overview/usage.csv')
|
||||
|
@ -1639,7 +1658,7 @@ class SeleniumTests(test.SeleniumAdminTestCase):
|
|||
|
||||
# Check the presence of the important elements
|
||||
td_element = self.selenium.find_element_by_xpath(
|
||||
"//td[@data-update-url='/admin/projects/?action=cell_update"
|
||||
"//td[@data-update-url='/identity/?action=cell_update"
|
||||
"&table=tenants&cell_name=name&obj_id=1']")
|
||||
cell_wrapper = td_element.find_element_by_class_name(
|
||||
'table_cell_wrapper')
|
||||
|
@ -1656,7 +1675,7 @@ class SeleniumTests(test.SeleniumAdminTestCase):
|
|||
wait.until(lambda x: self.selenium.find_element_by_name("name__1"))
|
||||
# Changing project name in cell form
|
||||
td_element = self.selenium.find_element_by_xpath(
|
||||
"//td[@data-update-url='/admin/projects/?action=cell_update"
|
||||
"//td[@data-update-url='/identity/?action=cell_update"
|
||||
"&table=tenants&cell_name=name&obj_id=1']")
|
||||
name_input = td_element.find_element_by_tag_name('input')
|
||||
name_input.send_keys(keys.Keys.HOME)
|
||||
|
@ -1667,13 +1686,13 @@ class SeleniumTests(test.SeleniumAdminTestCase):
|
|||
wait = self.ui.WebDriverWait(self.selenium, 10,
|
||||
ignored_exceptions=[socket_timeout])
|
||||
wait.until(lambda x: self.selenium.find_element_by_xpath(
|
||||
"//td[@data-update-url='/admin/projects/?action=cell_update"
|
||||
"//td[@data-update-url='/identity/?action=cell_update"
|
||||
"&table=tenants&cell_name=name&obj_id=1']"
|
||||
"/div[@class='table_cell_wrapper']"
|
||||
"/div[@class='table_cell_data_wrapper']"))
|
||||
# Checking new project name after cell refresh
|
||||
data_wrapper = self.selenium.find_element_by_xpath(
|
||||
"//td[@data-update-url='/admin/projects/?action=cell_update"
|
||||
"//td[@data-update-url='/identity/?action=cell_update"
|
||||
"&table=tenants&cell_name=name&obj_id=1']"
|
||||
"/div[@class='table_cell_wrapper']"
|
||||
"/div[@class='table_cell_data_wrapper']")
|
||||
|
@ -1703,7 +1722,7 @@ class SeleniumTests(test.SeleniumAdminTestCase):
|
|||
|
||||
# Check the presence of the important elements
|
||||
td_element = self.selenium.find_element_by_xpath(
|
||||
"//td[@data-update-url='/admin/projects/?action=cell_update"
|
||||
"//td[@data-update-url='/identity/?action=cell_update"
|
||||
"&table=tenants&cell_name=name&obj_id=1']")
|
||||
cell_wrapper = td_element.find_element_by_class_name(
|
||||
'table_cell_wrapper')
|
||||
|
@ -1720,13 +1739,13 @@ class SeleniumTests(test.SeleniumAdminTestCase):
|
|||
wait.until(lambda x: self.selenium.find_element_by_name("name__1"))
|
||||
# Click on cancel button
|
||||
td_element = self.selenium.find_element_by_xpath(
|
||||
"//td[@data-update-url='/admin/projects/?action=cell_update"
|
||||
"//td[@data-update-url='/identity/?action=cell_update"
|
||||
"&table=tenants&cell_name=name&obj_id=1']")
|
||||
td_element.find_element_by_class_name('inline-edit-cancel').click()
|
||||
# Cancel is via javascript, so it should be immediate
|
||||
# Checking that tenant name is not changed
|
||||
data_wrapper = self.selenium.find_element_by_xpath(
|
||||
"//td[@data-update-url='/admin/projects/?action=cell_update"
|
||||
"//td[@data-update-url='/identity/?action=cell_update"
|
||||
"&table=tenants&cell_name=name&obj_id=1']"
|
||||
"/div[@class='table_cell_wrapper']"
|
||||
"/div[@class='table_cell_data_wrapper']")
|
||||
|
@ -1768,7 +1787,7 @@ class SeleniumTests(test.SeleniumAdminTestCase):
|
|||
self.mox.ReplayAll()
|
||||
|
||||
self.selenium.get("%s%s" % (self.live_server_url,
|
||||
reverse('horizon:admin:projects:create')))
|
||||
reverse('horizon:identity:projects:create')))
|
||||
|
||||
members = self.selenium.find_element_by_css_selector(member_css_class)
|
||||
|
|
@ -19,7 +19,7 @@
|
|||
from django.conf.urls import patterns # noqa
|
||||
from django.conf.urls import url # noqa
|
||||
|
||||
from openstack_dashboard.dashboards.admin.projects import views
|
||||
from openstack_dashboard.dashboards.identity.projects import views
|
||||
|
||||
|
||||
urlpatterns = patterns('',
|
|
@ -20,18 +20,20 @@ from django.core.urlresolvers import reverse
|
|||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from horizon import exceptions
|
||||
from horizon import messages
|
||||
from horizon import tables
|
||||
from horizon.utils import memoized
|
||||
from horizon import workflows
|
||||
|
||||
from openstack_dashboard import api
|
||||
from openstack_dashboard.api import keystone
|
||||
from openstack_dashboard import policy
|
||||
from openstack_dashboard import usage
|
||||
from openstack_dashboard.usage import quotas
|
||||
|
||||
from openstack_dashboard.dashboards.admin.projects \
|
||||
from openstack_dashboard.dashboards.identity.projects \
|
||||
import tables as project_tables
|
||||
from openstack_dashboard.dashboards.admin.projects \
|
||||
from openstack_dashboard.dashboards.identity.projects \
|
||||
import workflows as project_workflows
|
||||
from openstack_dashboard.dashboards.project.overview \
|
||||
import views as project_views
|
||||
|
@ -42,7 +44,7 @@ PROJECT_INFO_FIELDS = ("domain_id",
|
|||
"description",
|
||||
"enabled")
|
||||
|
||||
INDEX_URL = "horizon:admin:projects:index"
|
||||
INDEX_URL = "horizon:identity:projects:index"
|
||||
|
||||
|
||||
class TenantContextMixin(object):
|
||||
|
@ -64,7 +66,7 @@ class TenantContextMixin(object):
|
|||
|
||||
class IndexView(tables.DataTableView):
|
||||
table_class = project_tables.TenantsTable
|
||||
template_name = 'admin/projects/index.html'
|
||||
template_name = 'identity/projects/index.html'
|
||||
|
||||
def has_more_data(self, table):
|
||||
return self._more
|
||||
|
@ -74,23 +76,43 @@ class IndexView(tables.DataTableView):
|
|||
marker = self.request.GET.get(
|
||||
project_tables.TenantsTable._meta.pagination_param, None)
|
||||
domain_context = self.request.session.get('domain_context', None)
|
||||
try:
|
||||
tenants, self._more = api.keystone.tenant_list(
|
||||
self.request,
|
||||
domain=domain_context,
|
||||
paginate=True,
|
||||
marker=marker)
|
||||
except Exception:
|
||||
if policy.check((("identity", "identity:list_projects"),),
|
||||
self.request):
|
||||
try:
|
||||
tenants, self._more = api.keystone.tenant_list(
|
||||
self.request,
|
||||
domain=domain_context,
|
||||
paginate=True,
|
||||
marker=marker)
|
||||
except Exception:
|
||||
self._more = False
|
||||
exceptions.handle(self.request,
|
||||
_("Unable to retrieve project list."))
|
||||
elif policy.check((("identity", "identity:list_user_projects"),),
|
||||
self.request):
|
||||
try:
|
||||
tenants, self._more = api.keystone.tenant_list(
|
||||
self.request,
|
||||
user=self.request.user.id,
|
||||
paginate=True,
|
||||
marker=marker,
|
||||
admin=False)
|
||||
except Exception:
|
||||
self._more = False
|
||||
exceptions.handle(self.request,
|
||||
_("Unable to retrieve project information."))
|
||||
else:
|
||||
self._more = False
|
||||
exceptions.handle(self.request,
|
||||
_("Unable to retrieve project list."))
|
||||
msg = \
|
||||
_("Insufficient privilege level to view project information.")
|
||||
messages.info(self.request, msg)
|
||||
return tenants
|
||||
|
||||
|
||||
class ProjectUsageView(usage.UsageView):
|
||||
table_class = usage.ProjectUsageTable
|
||||
usage_class = usage.ProjectUsage
|
||||
template_name = 'admin/projects/usage.html'
|
||||
template_name = 'identity/projects/usage.html'
|
||||
csv_response_class = project_views.ProjectUsageCsvRenderer
|
||||
csv_template_name = 'project/overview/usage.csv'
|
||||
|
|
@ -33,8 +33,8 @@ from openstack_dashboard.api import keystone
|
|||
from openstack_dashboard.api import nova
|
||||
from openstack_dashboard.usage import quotas
|
||||
|
||||
INDEX_URL = "horizon:admin:projects:index"
|
||||
ADD_USER_URL = "horizon:admin:projects:create_user"
|
||||
INDEX_URL = "horizon:identity:projects:index"
|
||||
ADD_USER_URL = "horizon:identity:projects:create_user"
|
||||
PROJECT_GROUP_ENABLED = keystone.VERSIONS.active >= 3
|
||||
PROJECT_USER_MEMBER_SLUG = "update_members"
|
||||
PROJECT_GROUP_MEMBER_SLUG = "update_group_members"
|
||||
|
@ -340,7 +340,7 @@ class CreateProject(workflows.Workflow):
|
|||
finalize_button_name = _("Create Project")
|
||||
success_message = _('Created new project "%s".')
|
||||
failure_message = _('Unable to create project "%s".')
|
||||
success_url = "horizon:admin:projects:index"
|
||||
success_url = "horizon:identity:projects:index"
|
||||
default_steps = (CreateProjectInfo,
|
||||
UpdateProjectMembers,
|
||||
UpdateProjectQuota)
|
||||
|
@ -493,7 +493,7 @@ class UpdateProject(workflows.Workflow):
|
|||
finalize_button_name = _("Save")
|
||||
success_message = _('Modified project "%s".')
|
||||
failure_message = _('Unable to modify project "%s".')
|
||||
success_url = "horizon:admin:projects:index"
|
||||
success_url = "horizon:identity:projects:index"
|
||||
default_steps = (UpdateProjectInfo,
|
||||
UpdateProjectMembers,
|
||||
UpdateProjectQuota)
|
|
@ -17,12 +17,14 @@ from django.utils.translation import ugettext_lazy as _
|
|||
import horizon
|
||||
|
||||
from openstack_dashboard.api import keystone
|
||||
from openstack_dashboard.dashboards.admin import dashboard
|
||||
from openstack_dashboard.dashboards.identity import dashboard
|
||||
|
||||
|
||||
class Roles(horizon.Panel):
|
||||
name = _("Roles")
|
||||
slug = 'roles'
|
||||
policy_rules = (("identity", "identity:list_roles"),)
|
||||
|
||||
|
||||
if keystone.VERSIONS.active >= 3:
|
||||
dashboard.Admin.register(Roles)
|
||||
dashboard.Identity.register(Roles)
|
|
@ -22,7 +22,7 @@ from openstack_dashboard import api
|
|||
class CreateRoleLink(tables.LinkAction):
|
||||
name = "create"
|
||||
verbose_name = _("Create Role")
|
||||
url = "horizon:admin:roles:create"
|
||||
url = "horizon:identity:roles:create"
|
||||
classes = ("ajax-modal",)
|
||||
icon = "plus"
|
||||
policy_rules = (("identity", "identity:create_role"),)
|
||||
|
@ -34,7 +34,7 @@ class CreateRoleLink(tables.LinkAction):
|
|||
class EditRoleLink(tables.LinkAction):
|
||||
name = "edit"
|
||||
verbose_name = _("Edit")
|
||||
url = "horizon:admin:roles:update"
|
||||
url = "horizon:identity:roles:update"
|
||||
classes = ("ajax-modal",)
|
||||
icon = "pencil"
|
||||
policy_rules = (("identity", "identity:update_role"),)
|
|
@ -3,7 +3,7 @@
|
|||
{% load url from future %}
|
||||
|
||||
{% block form_id %}create_role_form{% endblock %}
|
||||
{% block form_action %}{% url 'horizon:admin:roles:create' %}{% endblock %}
|
||||
{% block form_action %}{% url 'horizon:identity:roles:create' %}{% endblock %}
|
||||
|
||||
{% block modal-header %}{% trans "Create Role" %}{% endblock %}
|
||||
|
||||
|
@ -21,5 +21,5 @@
|
|||
|
||||
{% block modal-footer %}
|
||||
<input class="btn btn-primary pull-right" type="submit" value="{% trans "Create Role" %}" />
|
||||
<a href="{% url 'horizon:admin:roles:index' %}" class="btn btn-default secondary cancel close">{% trans "Cancel" %}</a>
|
||||
<a href="{% url 'horizon:identity:roles:index' %}" class="btn btn-default secondary cancel close">{% trans "Cancel" %}</a>
|
||||
{% endblock %}
|
|
@ -3,7 +3,7 @@
|
|||
{% load url from future %}
|
||||
|
||||
{% block form_id %}update_role_form{% endblock %}
|
||||
{% block form_action %}{% url 'horizon:admin:roles:update' role.id %}{% endblock %}
|
||||
{% block form_action %}{% url 'horizon:identity:roles:update' role.id %}{% endblock %}
|
||||
|
||||
{% block modal-header %}{% trans "Update Role" %}{% endblock %}
|
||||
|
||||
|
@ -21,5 +21,5 @@
|
|||
|
||||
{% block modal-footer %}
|
||||
<input class="btn btn-primary pull-right" type="submit" value="{% trans "Update Role" %}" />
|
||||
<a href="{% url 'horizon:admin:roles:index' %}" class="btn btn-default secondary cancel close">{% trans "Cancel" %}</a>
|
||||
<a href="{% url 'horizon:identity:roles:index' %}" class="btn btn-default secondary cancel close">{% trans "Cancel" %}</a>
|
||||
{% endblock %}
|
|
@ -8,5 +8,5 @@
|
|||
{% endblock page_header %}
|
||||
|
||||
{% block main %}
|
||||
{% include 'admin/roles/_create.html' %}
|
||||
{% include 'identity/roles/_create.html' %}
|
||||
{% endblock %}
|
|
@ -8,5 +8,5 @@
|
|||
{% endblock page_header %}
|
||||
|
||||
{% block main %}
|
||||
{% include 'admin/roles/_update.html' %}
|
||||
{% include 'identity/roles/_update.html' %}
|
||||
{% endblock %}
|
|
@ -22,9 +22,9 @@ from openstack_dashboard import api
|
|||
from openstack_dashboard.test import helpers as test
|
||||
|
||||
|
||||
ROLES_INDEX_URL = reverse('horizon:admin:roles:index')
|
||||
ROLES_CREATE_URL = reverse('horizon:admin:roles:create')
|
||||
ROLES_UPDATE_URL = reverse('horizon:admin:roles:update', args=[1])
|
||||
ROLES_INDEX_URL = reverse('horizon:identity:roles:index')
|
||||
ROLES_CREATE_URL = reverse('horizon:identity:roles:create')
|
||||
ROLES_UPDATE_URL = reverse('horizon:identity:roles:update', args=[1])
|
||||
|
||||
|
||||
class RolesViewTests(test.BaseAdminViewTests):
|
||||
|
@ -39,7 +39,7 @@ class RolesViewTests(test.BaseAdminViewTests):
|
|||
self.assertContains(res, 'Edit')
|
||||
self.assertContains(res, 'Delete Role')
|
||||
|
||||
self.assertTemplateUsed(res, 'admin/roles/index.html')
|
||||
self.assertTemplateUsed(res, 'identity/roles/index.html')
|
||||
self.assertItemsEqual(res.context['table'].data, self.roles.list())
|
||||
|
||||
@test.create_stubs({api.keystone: ('role_list',
|
||||
|
@ -56,7 +56,7 @@ class RolesViewTests(test.BaseAdminViewTests):
|
|||
self.assertNotContains(res, 'Edit')
|
||||
self.assertNotContains(res, 'Delete Role')
|
||||
|
||||
self.assertTemplateUsed(res, 'admin/roles/index.html')
|
||||
self.assertTemplateUsed(res, 'identity/roles/index.html')
|
||||
self.assertItemsEqual(res.context['table'].data, self.roles.list())
|
||||
|
||||
@test.create_stubs({api.keystone: ('role_create', )})
|
|
@ -15,9 +15,9 @@
|
|||
from django.conf.urls import patterns # noqa
|
||||
from django.conf.urls import url # noqa
|
||||
|
||||
from openstack_dashboard.dashboards.admin.roles import views
|
||||
from openstack_dashboard.dashboards.identity.roles import views
|
||||
|
||||
urlpatterns = patterns('openstack_dashboard.dashboards.admin.roles.views',
|
||||
urlpatterns = patterns('openstack_dashboard.dashboards.identity.roles.views',
|
||||
url(r'^$', views.IndexView.as_view(), name='index'),
|
||||
url(r'^(?P<role_id>[^/]+)/update/$',
|
||||
views.UpdateView.as_view(), name='update'),
|
|
@ -18,42 +18,49 @@ from django.utils.translation import ugettext_lazy as _
|
|||
|
||||
from horizon import exceptions
|
||||
from horizon import forms
|
||||
from horizon import messages
|
||||
from horizon import tables
|
||||
from horizon.utils import memoized
|
||||
|
||||
from openstack_dashboard import api
|
||||
from openstack_dashboard import policy
|
||||
|
||||
from openstack_dashboard.dashboards.admin.roles \
|
||||
from openstack_dashboard.dashboards.identity.roles \
|
||||
import forms as project_forms
|
||||
from openstack_dashboard.dashboards.admin.roles \
|
||||
from openstack_dashboard.dashboards.identity.roles \
|
||||
import tables as project_tables
|
||||
|
||||
|
||||
class IndexView(tables.DataTableView):
|
||||
table_class = project_tables.RolesTable
|
||||
template_name = 'admin/roles/index.html'
|
||||
template_name = 'identity/roles/index.html'
|
||||
|
||||
def get_data(self):
|
||||
roles = []
|
||||
try:
|
||||
roles = api.keystone.role_list(self.request)
|
||||
except Exception:
|
||||
exceptions.handle(self.request,
|
||||
_('Unable to retrieve roles list.'))
|
||||
if policy.check((("identity", "identity:list_roles"),),
|
||||
self.request):
|
||||
try:
|
||||
roles = api.keystone.role_list(self.request)
|
||||
except Exception:
|
||||
exceptions.handle(self.request,
|
||||
_('Unable to retrieve roles list.'))
|
||||
else:
|
||||
msg = _("Insufficient privilege level to view role information.")
|
||||
messages.info(self.request, msg)
|
||||
return roles
|
||||
|
||||
|
||||
class UpdateView(forms.ModalFormView):
|
||||
form_class = project_forms.UpdateRoleForm
|
||||
template_name = 'admin/roles/update.html'
|
||||
success_url = reverse_lazy('horizon:admin:roles:index')
|
||||
template_name = 'identity/roles/update.html'
|
||||
success_url = reverse_lazy('horizon:identity:roles:index')
|
||||
|
||||
@memoized.memoized_method
|
||||
def get_object(self):
|
||||
try:
|
||||
return api.keystone.role_get(self.request, self.kwargs['role_id'])
|
||||
except Exception:
|
||||
redirect = reverse("horizon:admin:roles:index")
|
||||
redirect = reverse("horizon:identity:roles:index")
|
||||
exceptions.handle(self.request,
|
||||
_('Unable to update role.'),
|
||||
redirect=redirect)
|
||||
|
@ -71,5 +78,5 @@ class UpdateView(forms.ModalFormView):
|
|||
|
||||
class CreateView(forms.ModalFormView):
|
||||
form_class = project_forms.CreateRoleForm
|
||||
template_name = 'admin/roles/create.html'
|
||||
success_url = reverse_lazy('horizon:admin:roles:index')
|
||||
template_name = 'identity/roles/create.html'
|
||||
success_url = reverse_lazy('horizon:identity:roles:index')
|
|
@ -67,7 +67,7 @@ class BaseUserForm(forms.SelfHandlingForm):
|
|||
return data
|
||||
|
||||
|
||||
ADD_PROJECT_URL = "horizon:admin:projects:create"
|
||||
ADD_PROJECT_URL = "horizon:identity:projects:create"
|
||||
|
||||
|
||||
class CreateUserForm(BaseUserForm):
|
|
@ -20,12 +20,14 @@ from django.utils.translation import ugettext_lazy as _
|
|||
|
||||
import horizon
|
||||
|
||||
from openstack_dashboard.dashboards.admin import dashboard
|
||||
from openstack_dashboard.dashboards.identity import dashboard
|
||||
|
||||
|
||||
class Users(horizon.Panel):
|
||||
name = _("Users")
|
||||
slug = 'users'
|
||||
policy_rules = (("identity", "identity:get_user"),
|
||||
("identity", "identity:list_users"))
|
||||
|
||||
|
||||
dashboard.Admin.register(Users)
|
||||
dashboard.Identity.register(Users)
|
|
@ -26,7 +26,7 @@ DISABLE = 1
|
|||
class CreateUserLink(tables.LinkAction):
|
||||
name = "create"
|
||||
verbose_name = _("Create User")
|
||||
url = "horizon:admin:users:create"
|
||||
url = "horizon:identity:users:create"
|
||||
classes = ("ajax-modal",)
|
||||
icon = "plus"
|
||||
policy_rules = (('identity', 'identity:create_grant'),
|
||||
|
@ -41,7 +41,7 @@ class CreateUserLink(tables.LinkAction):
|
|||
class EditUserLink(tables.LinkAction):
|
||||
name = "edit"
|
||||
verbose_name = _("Edit")
|
||||
url = "horizon:admin:users:update"
|
||||
url = "horizon:identity:users:update"
|
||||
classes = ("ajax-modal",)
|
||||
icon = "pencil"
|
||||
policy_rules = (("identity", "identity:update_user"),
|
|
@ -3,7 +3,7 @@
|
|||
{% load url from future %}
|
||||
|
||||
{% block form_id %}create_user_form{% endblock %}
|
||||
{% block form_action %}{% url 'horizon:admin:users:create' %}{% endblock %}
|
||||
{% block form_action %}{% url 'horizon:identity:users:create' %}{% endblock %}
|
||||
|
||||
{% block modal-header %}{% trans "Create User" %}{% endblock %}
|
||||
|
||||
|
@ -31,5 +31,5 @@
|
|||
|
||||
{% block modal-footer %}
|
||||
<input class="btn btn-primary pull-right" type="submit" value="{% trans "Create User" %}" />
|
||||
<a href="{% url 'horizon:admin:users:index' %}" class="btn btn-default secondary cancel close">{% trans "Cancel" %}</a>
|
||||
<a href="{% url 'horizon:identity:users:index' %}" class="btn btn-default secondary cancel close">{% trans "Cancel" %}</a>
|
||||
{% endblock %}
|
|
@ -3,7 +3,7 @@
|
|||
{% load url from future %}
|
||||
|
||||
{% block form_id %}update_user_form{% endblock %}
|
||||
{% block form_action %}{% url 'horizon:admin:users:update' user.id %}{% endblock %}
|
||||
{% block form_action %}{% url 'horizon:identity:users:update' user.id %}{% endblock %}
|
||||
|
||||
{% block modal-header %}{% trans "Update User" %}{% endblock %}
|
||||
|
||||
|
@ -31,5 +31,5 @@
|
|||
|
||||
{% block modal-footer %}
|
||||
<input class="btn btn-primary pull-right" type="submit" value="{% trans "Update User" %}" />
|
||||
<a href="{% url 'horizon:admin:users:index' %}" class="btn btn-default secondary cancel close">{% trans "Cancel" %}</a>
|
||||
<a href="{% url 'horizon:identity:users:index' %}" class="btn btn-default secondary cancel close">{% trans "Cancel" %}</a>
|
||||
{% endblock %}
|
|
@ -8,5 +8,5 @@
|
|||
{% endblock page_header %}
|
||||
|
||||
{% block main %}
|
||||
{% include 'admin/users/_create.html' %}
|
||||
{% include 'identity/users/_create.html' %}
|
||||
{% endblock %}
|
|
@ -8,5 +8,5 @@
|
|||
{% endblock page_header %}
|
||||
|
||||
{% block main %}
|
||||
{% include 'admin/users/_update.html' %}
|
||||
{% include 'identity/users/_update.html' %}
|
||||
{% endblock %}
|
|
@ -28,9 +28,9 @@ from openstack_dashboard import api
|
|||
from openstack_dashboard.test import helpers as test
|
||||
|
||||
|
||||
USERS_INDEX_URL = reverse('horizon:admin:users:index')
|
||||
USER_CREATE_URL = reverse('horizon:admin:users:create')
|
||||
USER_UPDATE_URL = reverse('horizon:admin:users:update', args=[1])
|
||||
USERS_INDEX_URL = reverse('horizon:identity:users:index')
|
||||
USER_CREATE_URL = reverse('horizon:identity:users:create')
|
||||
USER_UPDATE_URL = reverse('horizon:identity:users:update', args=[1])
|
||||
|
||||
|
||||
class UsersViewTests(test.BaseAdminViewTests):
|
||||
|
@ -59,7 +59,7 @@ class UsersViewTests(test.BaseAdminViewTests):
|
|||
|
||||
self.mox.ReplayAll()
|
||||
res = self.client.get(USERS_INDEX_URL)
|
||||
self.assertTemplateUsed(res, 'admin/users/index.html')
|
||||
self.assertTemplateUsed(res, 'identity/users/index.html')
|
||||
self.assertItemsEqual(res.context['table'].data, users)
|
||||
|
||||
if domain_id:
|
|
@ -19,9 +19,9 @@
|
|||
from django.conf.urls import patterns # noqa
|
||||
from django.conf.urls import url # noqa
|
||||
|
||||
from openstack_dashboard.dashboards.admin.users import views
|
||||
from openstack_dashboard.dashboards.identity.users import views
|
||||
|
||||
urlpatterns = patterns('openstack_dashboard.dashboards.admin.users.views',
|
||||
urlpatterns = patterns('openstack_dashboard.dashboards.identity.users.views',
|
||||
url(r'^$', views.IndexView.as_view(), name='index'),
|
||||
url(r'^(?P<user_id>[^/]+)/update/$',
|
||||
views.UpdateView.as_view(), name='update'),
|
|
@ -26,37 +26,53 @@ from django.views.decorators.debug import sensitive_post_parameters # noqa
|
|||
|
||||
from horizon import exceptions
|
||||
from horizon import forms
|
||||
from horizon import messages
|
||||
from horizon import tables
|
||||
from horizon.utils import memoized
|
||||
|
||||
from openstack_dashboard import api
|
||||
from openstack_dashboard import policy
|
||||
|
||||
from openstack_dashboard.dashboards.admin.users \
|
||||
from openstack_dashboard.dashboards.identity.users \
|
||||
import forms as project_forms
|
||||
from openstack_dashboard.dashboards.admin.users \
|
||||
from openstack_dashboard.dashboards.identity.users \
|
||||
import tables as project_tables
|
||||
|
||||
|
||||
class IndexView(tables.DataTableView):
|
||||
table_class = project_tables.UsersTable
|
||||
template_name = 'admin/users/index.html'
|
||||
template_name = 'identity/users/index.html'
|
||||
|
||||
def get_data(self):
|
||||
users = []
|
||||
domain_context = self.request.session.get('domain_context', None)
|
||||
try:
|
||||
users = api.keystone.user_list(self.request,
|
||||
domain=domain_context)
|
||||
except Exception:
|
||||
exceptions.handle(self.request,
|
||||
_('Unable to retrieve user list.'))
|
||||
if policy.check((("identity", "identity:list_users"),),
|
||||
self.request):
|
||||
try:
|
||||
users = api.keystone.user_list(self.request,
|
||||
domain=domain_context)
|
||||
except Exception:
|
||||
exceptions.handle(self.request,
|
||||
_('Unable to retrieve user list.'))
|
||||
elif policy.check((("identity", "identity:get_user"),),
|
||||
self.request):
|
||||
try:
|
||||
user = api.keystone.user_get(self.request,
|
||||
self.request.user.id)
|
||||
users.append(user)
|
||||
except Exception:
|
||||
exceptions.handle(self.request,
|
||||
_('Unable to retrieve user information.'))
|
||||
else:
|
||||
msg = _("Insufficient privilege level to view user information.")
|
||||
messages.info(self.request, msg)
|
||||
return users
|
||||
|
||||
|
||||
class UpdateView(forms.ModalFormView):
|
||||
form_class = project_forms.UpdateUserForm
|
||||
template_name = 'admin/users/update.html'
|
||||
success_url = reverse_lazy('horizon:admin:users:index')
|
||||
template_name = 'identity/users/update.html'
|
||||
success_url = reverse_lazy('horizon:identity:users:index')
|
||||
|
||||
@method_decorator(sensitive_post_parameters('password',
|
||||
'confirm_password'))
|
||||
|
@ -69,7 +85,7 @@ class UpdateView(forms.ModalFormView):
|
|||
return api.keystone.user_get(self.request, self.kwargs['user_id'],
|
||||
admin=True)
|
||||
except Exception:
|
||||
redirect = reverse("horizon:admin:users:index")
|
||||
redirect = reverse("horizon:identity:users:index")
|
||||
exceptions.handle(self.request,
|
||||
_('Unable to update user.'),
|
||||
redirect=redirect)
|
||||
|
@ -102,8 +118,8 @@ class UpdateView(forms.ModalFormView):
|
|||
|
||||
class CreateView(forms.ModalFormView):
|
||||
form_class = project_forms.CreateUserForm
|
||||
template_name = 'admin/users/create.html'
|
||||
success_url = reverse_lazy('horizon:admin:users:index')
|
||||
template_name = 'identity/users/create.html'
|
||||
success_url = reverse_lazy('horizon:identity:users:index')
|
||||
|
||||
@method_decorator(sensitive_post_parameters('password',
|
||||
'confirm_password'))
|
||||
|
@ -115,7 +131,7 @@ class CreateView(forms.ModalFormView):
|
|||
try:
|
||||
roles = api.keystone.role_list(self.request)
|
||||
except Exception:
|
||||
redirect = reverse("horizon:admin:users:index")
|
||||
redirect = reverse("horizon:identity:users:index")
|
||||
exceptions.handle(self.request,
|
||||
_("Unable to retrieve user roles."),
|
||||
redirect=redirect)
|
|
@ -0,0 +1,8 @@
|
|||
# The name of the dashboard to be added to HORIZON['dashboards']. Required.
|
||||
DASHBOARD = 'identity'
|
||||
# If set to True, this dashboard will be set as the default dashboard.
|
||||
DEFAULT = False
|
||||
# A dictionary of exception classes to be added to HORIZON['exceptions'].
|
||||
ADD_EXCEPTIONS = {}
|
||||
# A list of applications to be added to INSTALLED_APPS.
|
||||
ADD_INSTALLED_APPS = ['openstack_dashboard.dashboards.identity']
|
|
@ -110,6 +110,9 @@ def check(actions, request, target={}):
|
|||
# same for user_id
|
||||
if target.get('user_id') is None:
|
||||
target['user_id'] = user.id
|
||||
# same for domain_id
|
||||
if target.get('domain_id') is None:
|
||||
target['domain_id'] = user.domain_id
|
||||
|
||||
credentials = _user_to_credentials(request, user)
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ STATIC_URL = '/static/'
|
|||
ROOT_URLCONF = 'openstack_dashboard.urls'
|
||||
|
||||
HORIZON_CONFIG = {
|
||||
'dashboards': ('project', 'admin', 'settings', 'router',),
|
||||
'dashboards': ('project', 'admin', 'router',),
|
||||
'default_dashboard': 'project',
|
||||
'user_home': 'openstack_dashboard.views.get_user_home',
|
||||
'ajax_queue_limit': 10,
|
||||
|
|
|
@ -45,6 +45,7 @@ INSTALLED_APPS = (
|
|||
'openstack_dashboard',
|
||||
'openstack_dashboard.dashboards.project',
|
||||
'openstack_dashboard.dashboards.admin',
|
||||
'openstack_dashboard.dashboards.identity',
|
||||
'openstack_dashboard.dashboards.settings',
|
||||
'openstack_dashboard.dashboards.router',
|
||||
)
|
||||
|
@ -54,7 +55,7 @@ AUTHENTICATION_BACKENDS = ('openstack_auth.backend.KeystoneBackend',)
|
|||
SITE_BRANDING = 'OpenStack'
|
||||
|
||||
HORIZON_CONFIG = {
|
||||
'dashboards': ('project', 'admin', 'settings', 'router',),
|
||||
'dashboards': ('project', 'admin', 'identity', 'settings', 'router',),
|
||||
'default_dashboard': 'project',
|
||||
"password_validator": {
|
||||
"regex": '^.{8,18}$',
|
||||
|
|
Loading…
Reference in New Issue