244 lines
7.8 KiB
Python
244 lines
7.8 KiB
Python
# Copyright 2012 Nebula, Inc.
|
|
#
|
|
# 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 __future__ import absolute_import
|
|
|
|
from collections import OrderedDict
|
|
from horizon.contrib import bootstrap_datepicker
|
|
|
|
from django.conf import settings
|
|
from django import template
|
|
from django.template import Node
|
|
from django.utils.encoding import force_text
|
|
from django.utils import translation
|
|
from django.utils.translation import ugettext_lazy as _
|
|
|
|
from horizon.base import Horizon
|
|
from horizon import conf
|
|
|
|
|
|
register = template.Library()
|
|
|
|
|
|
class MinifiedNode(Node):
|
|
def __init__(self, nodelist):
|
|
self.nodelist = nodelist
|
|
|
|
def render(self, context):
|
|
return ' '.join(
|
|
force_text(self.nodelist.render(context).strip()).split()
|
|
).replace(' > ', '>').replace(' <', '<')
|
|
|
|
|
|
@register.filter
|
|
def has_permissions(user, component):
|
|
"""Checks if the given user meets the permissions requirements for
|
|
the component.
|
|
"""
|
|
return user.has_perms(getattr(component, 'permissions', set()))
|
|
|
|
|
|
@register.filter
|
|
def has_permissions_on_list(components, user):
|
|
return [component for component
|
|
in components if has_permissions(user, component)]
|
|
|
|
|
|
@register.inclusion_tag('horizon/_sidebar.html', takes_context=True)
|
|
def horizon_nav(context):
|
|
if 'request' not in context:
|
|
return {}
|
|
current_dashboard = context['request'].horizon.get('dashboard', None)
|
|
current_panel_group = None
|
|
current_panel = context['request'].horizon.get('panel', None)
|
|
dashboards = []
|
|
for dash in Horizon.get_dashboards():
|
|
panel_groups = dash.get_panel_groups()
|
|
non_empty_groups = []
|
|
for group in panel_groups.values():
|
|
allowed_panels = []
|
|
for panel in group:
|
|
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 and
|
|
panel.can_access(context)):
|
|
allowed_panels.append(panel)
|
|
if panel == current_panel:
|
|
current_panel_group = group.slug
|
|
if allowed_panels:
|
|
non_empty_groups.append((group, allowed_panels))
|
|
if (callable(dash.nav) and dash.nav(context) and
|
|
dash.can_access(context)):
|
|
dashboards.append((dash, OrderedDict(non_empty_groups)))
|
|
elif (not callable(dash.nav) and dash.nav and
|
|
dash.can_access(context)):
|
|
dashboards.append((dash, OrderedDict(non_empty_groups)))
|
|
return {'components': dashboards,
|
|
'user': context['request'].user,
|
|
'current': current_dashboard,
|
|
'current_panel_group': current_panel_group,
|
|
'current_panel': current_panel.slug if current_panel else '',
|
|
'request': context['request']}
|
|
|
|
|
|
@register.inclusion_tag('horizon/_nav_list.html', takes_context=True)
|
|
def horizon_main_nav(context):
|
|
"""Generates top-level dashboard navigation entries."""
|
|
if 'request' not in context:
|
|
return {}
|
|
current_dashboard = context['request'].horizon.get('dashboard', None)
|
|
dashboards = []
|
|
for dash in Horizon.get_dashboards():
|
|
if dash.can_access(context):
|
|
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,
|
|
'request': context['request']}
|
|
|
|
|
|
@register.inclusion_tag('horizon/_subnav_list.html', takes_context=True)
|
|
def horizon_dashboard_nav(context):
|
|
"""Generates sub-navigation entries for the current dashboard."""
|
|
if 'request' not in context:
|
|
return {}
|
|
dashboard = context['request'].horizon['dashboard']
|
|
panel_groups = dashboard.get_panel_groups()
|
|
non_empty_groups = []
|
|
|
|
for group in panel_groups.values():
|
|
allowed_panels = []
|
|
for panel in group:
|
|
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 and
|
|
panel.can_access(context)):
|
|
allowed_panels.append(panel)
|
|
if allowed_panels:
|
|
if group.name is None:
|
|
non_empty_groups.append((dashboard.name, allowed_panels))
|
|
else:
|
|
non_empty_groups.append((group.name, allowed_panels))
|
|
|
|
return {'components': OrderedDict(non_empty_groups),
|
|
'user': context['request'].user,
|
|
'current': context['request'].horizon['panel'].slug,
|
|
'request': context['request']}
|
|
|
|
|
|
@register.filter
|
|
def quota(val, units=None):
|
|
if val == float("inf"):
|
|
return _("(No Limit)")
|
|
elif units is not None:
|
|
return "%s %s %s" % (val, force_text(units),
|
|
force_text(_("Available")))
|
|
else:
|
|
return "%s %s" % (val, force_text(_("Available")))
|
|
|
|
|
|
@register.filter
|
|
def quotainf(val, units=None):
|
|
if val == float("inf"):
|
|
return '-1'
|
|
elif units is not None:
|
|
return "%s %s" % (val, units)
|
|
else:
|
|
return val
|
|
|
|
|
|
@register.simple_tag
|
|
def quotapercent(used, limit):
|
|
if used >= limit or limit == 0:
|
|
return 100
|
|
elif limit == float("inf"):
|
|
return '[%s, true]' % used
|
|
else:
|
|
return round((float(used) / float(limit)) * 100)
|
|
|
|
|
|
class JSTemplateNode(template.Node):
|
|
"""Helper node for the ``jstemplate`` template tag."""
|
|
def __init__(self, nodelist):
|
|
self.nodelist = nodelist
|
|
|
|
def render(self, context,):
|
|
output = self.nodelist.render(context)
|
|
output = output.replace('[[[', '{{{').replace(']]]', '}}}')
|
|
output = output.replace('[[', '{{').replace(']]', '}}')
|
|
output = output.replace('[%', '{%').replace('%]', '%}')
|
|
return output
|
|
|
|
|
|
@register.tag
|
|
def jstemplate(parser, token):
|
|
"""Replaces ``[[[`` and ``]]]`` with ``{{{`` and ``}}}``,
|
|
``[[`` and ``]]`` with ``{{`` and ``}}`` and
|
|
``[%`` and ``%]`` with ``{%`` and ``%}`` to avoid conflicts
|
|
with Django's template engine when using any of the Mustache-based
|
|
templating libraries.
|
|
"""
|
|
nodelist = parser.parse(('endjstemplate',))
|
|
parser.delete_first_token()
|
|
return JSTemplateNode(nodelist)
|
|
|
|
|
|
@register.assignment_tag
|
|
def load_config():
|
|
return conf
|
|
|
|
|
|
@register.assignment_tag
|
|
def datepicker_locale():
|
|
locale_mapping = getattr(settings, 'DATEPICKER_LOCALES',
|
|
bootstrap_datepicker.LOCALE_MAPPING)
|
|
return locale_mapping.get(translation.get_language(), 'en')
|
|
|
|
|
|
@register.assignment_tag
|
|
def template_cache_age():
|
|
return getattr(settings, 'NG_TEMPLATE_CACHE_AGE', 0)
|
|
|
|
|
|
@register.tag
|
|
def minifyspace(parser, token):
|
|
"""Removes whitespace including tab and newline characters.
|
|
|
|
Do not use this if you are using a <pre> tag.
|
|
|
|
Example usage::
|
|
|
|
{% minifyspace %}
|
|
<p>
|
|
<a title="foo"
|
|
href="foo/">
|
|
Foo
|
|
</a>
|
|
</p>
|
|
{% endminifyspace %}
|
|
|
|
This example would return this HTML::
|
|
|
|
<p><a title="foo" href="foo/">Foo</a></p>
|
|
|
|
"""
|
|
nodelist = parser.parse(('endminifyspace',))
|
|
parser.delete_first_token()
|
|
return MinifiedNode(nodelist)
|