combo/combo/public/templatetags/combo.py

194 lines
6.7 KiB
Python

# combo - content management system
# Copyright (C) 2014 Entr'ouvert
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from __future__ import absolute_import
import datetime
from django import template
from django.core.exceptions import PermissionDenied
from django.template import RequestContext
from django.template.base import TOKEN_BLOCK, TOKEN_VAR
from django.utils import dateparse
from combo.data.models import Placeholder
from combo.public.menu import get_menu_context
from combo.utils import NothingInCacheException
from combo.apps.dashboard.models import DashboardCell, Tile
register = template.Library()
def skeleton_text(context, placeholder_name, content=''):
if context['request'].GET.get('format') == 'ezt':
return '[if-any %s][%s][end]' % (placeholder_name, placeholder_name)
return '{%% block placeholder-%s %%}{%% block %s %%}%s{%% endblock %%}{%% endblock %%}' % (
placeholder_name, placeholder_name, content)
@register.inclusion_tag('combo/placeholder.html', takes_context=True)
def placeholder(context, placeholder_name, **options):
placeholder = Placeholder(key=placeholder_name, **options)
if context.get('placeholder_search_mode'):
if placeholder.name:
# only include placeholders with a name
context['placeholders'].append(placeholder)
if not context['traverse_cells']:
return context
context['render'] = True
if not placeholder.render:
context['render'] = False
return context
page_cells = []
if 'page_cells' in context:
# page cells are not precomputed when rendering a single cell in an
# ajax call
page_cells = context.get('page_cells')
elif not context.get('render_skeleton'):
page_cells = context['page'].get_cells()
context['cells'] = [x for x in page_cells if
x.placeholder == placeholder_name and
(context.get('render_skeleton') or x.is_relevant(context))]
if context.get('render_skeleton') and not context['cells']:
context['skeleton'] = skeleton_text(context, placeholder_name)
else:
context['skeleton'] = ''
return context
@register.simple_tag(takes_context=True)
def render_cell(context, cell):
if context.get('render_skeleton') and cell.is_user_dependant(context):
return template.loader.get_template('combo/deferred-cell.html').render(context)
in_dashboard = False
if DashboardCell.is_enabled():
# check if cell is actually a dashboard tile
try:
tile = Tile.get_by_cell(cell)
except Tile.DoesNotExist:
pass
else:
if context['request'].user != tile.user:
raise PermissionDenied()
in_dashboard = True
context['in_dashboard'] = in_dashboard
try:
return cell.render(context)
except NothingInCacheException:
return template.loader.get_template('combo/deferred-cell.html').render(context)
@register.tag
def skeleton_extra_placeholder(parser, token):
try:
tag_name, placeholder_name = token.split_contents()
except ValueError:
raise template.TemplateSyntaxError(
"%r tag requires exactly one argument" % token.contents.split()[0]
)
tokens_copy = parser.tokens[:]
text = []
while True:
token = tokens_copy.pop(0)
if token.contents == 'end_skeleton_extra_placeholder':
break
if token.token_type == TOKEN_VAR:
text.append('{{')
elif token.token_type == TOKEN_BLOCK:
text.append('{%')
text.append(token.contents)
if token.token_type == TOKEN_VAR:
text.append('}}')
elif token.token_type == TOKEN_BLOCK:
text.append('%}')
nodelist = parser.parse(('end_skeleton_extra_placeholder',))
parser.delete_first_token()
return ExtraPlaceholderNode(nodelist, placeholder_name, ''.join(text))
class ExtraPlaceholderNode(template.Node):
def __init__(self, nodelist, placeholder_name, content):
self.nodelist = nodelist
self.placeholder_name = placeholder_name
self.content = content
def render(self, context):
if not context.get('render_skeleton'):
return self.nodelist.render(context)
return skeleton_text(context, self.placeholder_name, content=self.content)
@register.inclusion_tag('combo/menu.html', takes_context=True)
def show_menu(context, level=0, current_page=None, depth=1, reduce_depth=False):
if reduce_depth:
depth -= 1
new_context = RequestContext(context['request'], {
'page': context['page'],
'render_skeleton': context.get('render_skeleton'),
'request': context['request']})
return get_menu_context(new_context, level=level, current_page=current_page,
depth=depth)
@register.simple_tag(takes_context=True)
def page_absolute_url(context, page):
return context['request'].build_absolute_uri(page.get_online_url())
@register.filter(name='strptime')
def strptime(date_string, date_format):
try:
return datetime.datetime.strptime(date_string, date_format)
except ValueError:
return None
@register.filter
def parse_datetime(date_string):
try:
return dateparse.parse_datetime(date_string)
except ValueError:
return None
@register.filter
def shown_because_admin(cell, request):
if not (request.user and request.user.is_superuser):
return False
if cell.public:
return False
cell_groups = cell.groups.all()
if not cell_groups:
return False
return not(set(cell_groups).intersection(request.user.groups.all()))
@register.filter(name='has_role')
def has_role(user, groupname):
if not user or user.is_anonymous():
return False
return user.groups.filter(name=groupname).exists()
@register.filter(name='get')
def get(obj, key):
try:
return obj.get(key)
except AttributeError:
return None
@register.filter(name='get_group')
def get_group(group_list, group_name):
ret = []
for group in group_list:
if group['grouper'] == group_name:
ret.extend(group['list'])
return ret