/
plugins.py
129 lines (119 loc) · 5.31 KB
/
plugins.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# -*- coding: utf-8 -*-
from cms.exceptions import DuplicatePlaceholderWarning
from cms.models import Page
from cms.templatetags.cms_tags import Placeholder
from django.contrib.sites.models import Site
from django.shortcuts import get_object_or_404
from django.template import NodeList, TextNode, VariableNode, \
TemplateSyntaxError
from django.template.loader import get_template
from django.template.loader_tags import ConstantIncludeNode, ExtendsNode, \
BlockNode
import warnings
def get_page_from_plugin_or_404(cms_plugin):
return get_object_or_404(Page, placeholders=cms_plugin.placeholder)
def _extend_blocks(extend_node, blocks):
"""
Extends the dictionary `blocks` with *new* blocks in the parent node (recursive)
"""
# we don't support variable extensions
if extend_node.parent_name_expr:
return
parent = extend_node.get_parent(None)
# Search for new blocks
for node in parent.nodelist.get_nodes_by_type(BlockNode):
if not node.name in blocks:
blocks[node.name] = node
else:
# set this node as the super node (for {{ block.super }})
blocks[node.name].super = node
# search for further ExtendsNodes
for node in parent.nodelist:
if not isinstance(node, TextNode):
if isinstance(node, ExtendsNode):
_extend_blocks(node, blocks)
break
def _extend_nodelist(extend_node):
"""
Returns a list of placeholders found in the parent template(s) of this
ExtendsNode
"""
# we don't support variable extensions
if extend_node.parent_name_expr:
return []
blocks = extend_node.blocks
_extend_blocks(extend_node, blocks)
placeholders = []
for block in blocks.values():
placeholders += _scan_placeholders(block.nodelist, block, blocks.keys())
parent_template = extend_node.get_parent({})
# if this is the topmost template, check for placeholders outside of blocks
if not parent_template.nodelist.get_nodes_by_type(ExtendsNode):
placeholders += _scan_placeholders(parent_template.nodelist, None, blocks.keys())
return placeholders
def _scan_placeholders(nodelist, current_block=None, ignore_blocks=[]):
placeholders = []
for node in nodelist:
# check if this is a placeholder first
if isinstance(node, Placeholder):
placeholders.append(node.get_name())
# if it's a Constant Include Node ({% include "template_name.html" %})
# scan the child template
elif isinstance(node, ConstantIncludeNode):
# if there's an error in the to-be-included template, node.template becomes None
if node.template:
placeholders += _scan_placeholders(node.template.nodelist, current_block)
# handle {% extends ... %} tags
elif isinstance(node, ExtendsNode):
placeholders += _extend_nodelist(node)
# in block nodes we have to scan for super blocks
elif isinstance(node, VariableNode) and current_block:
if node.filter_expression.token == 'block.super':
if not hasattr(current_block.super, 'nodelist'):
raise TemplateSyntaxError("Cannot render block.super for blocks without a parent.")
placeholders += _scan_placeholders(current_block.super.nodelist, current_block.super)
# ignore nested blocks which are already handled
elif isinstance(node, BlockNode) and node.name in ignore_blocks:
continue
# if the node has the newly introduced 'child_nodelists' attribute, scan
# those attributes for nodelists and recurse them
elif hasattr(node, 'child_nodelists'):
for nodelist_name in node.child_nodelists:
if hasattr(node, nodelist_name):
subnodelist = getattr(node, nodelist_name)
if isinstance(subnodelist, NodeList):
if isinstance(node, BlockNode):
current_block = node
placeholders += _scan_placeholders(subnodelist, current_block)
# else just scan the node for nodelist instance attributes
else:
for attr in dir(node):
obj = getattr(node, attr)
if isinstance(obj, NodeList):
if isinstance(node, BlockNode):
current_block = node
placeholders += _scan_placeholders(obj, current_block)
return placeholders
def get_placeholders(template):
compiled_template = get_template(template)
placeholders = _scan_placeholders(compiled_template.nodelist)
clean_placeholders = []
for placeholder in placeholders:
if placeholder in clean_placeholders:
warnings.warn("Duplicate placeholder found: `%s`" % placeholder, DuplicatePlaceholderWarning)
else:
clean_placeholders.append(placeholder)
return clean_placeholders
SITE_VAR = "site__exact"
def current_site(request):
if SITE_VAR in request.REQUEST:
return Site.objects.get(pk=request.REQUEST[SITE_VAR])
else:
site_pk = request.session.get('cms_admin_site', None)
if site_pk:
try:
return Site.objects.get(pk=site_pk)
except Site.DoesNotExist:
return None
else:
return Site.objects.get_current()