/
piwik.py
110 lines (84 loc) · 3.72 KB
/
piwik.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
"""
Piwik template tags and filters.
"""
from __future__ import absolute_import
from collections import namedtuple
from itertools import chain
import re
from django.template import Library, Node, TemplateSyntaxError
from analytical.utils import (is_internal_ip, disable_html,
get_required_setting, get_identity)
# domain name (characters separated by a dot), optional port, optional URI path, no slash
DOMAINPATH_RE = re.compile(r'^(([^./?#@:]+\.)*[^./?#@:]+)+(:[0-9]+)?(/[^/?#@:]+)*$')
# numeric ID
SITEID_RE = re.compile(r'^\d+$')
TRACKING_CODE = """
<script type="text/javascript">
var _paq = _paq || [];
%(variables)s
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function() {
var u=(("https:" == document.location.protocol) ? "https" : "http") + "://%(url)s/";
_paq.push(['setTrackerUrl', u+'piwik.php']);
_paq.push(['setSiteId', %(siteid)s]);
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; g.type='text/javascript';
g.defer=true; g.async=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s);
})();
</script>
<noscript><p><img src="http://%(url)s/piwik.php?idsite=%(siteid)s" style="border:0;" alt="" /></p></noscript>
""" # noqa
VARIABLE_CODE = '_paq.push(["setCustomVariable", %(index)s, "%(name)s", "%(value)s", "%(scope)s"]);' # noqa
IDENTITY_CODE = '_paq.push(["setUserId", "%(userid)s"]);'
DEFAULT_SCOPE = 'page'
PiwikVar = namedtuple('PiwikVar', ('index', 'name', 'value', 'scope'))
register = Library()
@register.tag
def piwik(parser, token):
"""
Piwik tracking template tag.
Renders Javascript code to track page visits. You must supply
your Piwik domain (plus optional URI path), and tracked site ID
in the ``PIWIK_DOMAIN_PATH`` and the ``PIWIK_SITE_ID`` setting.
Custom variables can be passed in the ``piwik_vars`` context
variable. It is an iterable of custom variables as tuples like:
``(index, name, value[, scope])`` where scope may be ``'page'``
(default) or ``'visit'``. Index should be an integer and the
other parameters should be strings.
"""
bits = token.split_contents()
if len(bits) > 1:
raise TemplateSyntaxError("'%s' takes no arguments" % bits[0])
return PiwikNode()
class PiwikNode(Node):
def __init__(self):
self.domain_path = \
get_required_setting('PIWIK_DOMAIN_PATH', DOMAINPATH_RE,
"must be a domain name, optionally followed "
"by an URI path, no trailing slash (e.g. "
"piwik.example.com or my.piwik.server/path)")
self.site_id = \
get_required_setting('PIWIK_SITE_ID', SITEID_RE,
"must be a (string containing a) number")
def render(self, context):
custom_variables = context.get('piwik_vars', ())
complete_variables = (var if len(var) >= 4 else var + (DEFAULT_SCOPE,)
for var in custom_variables)
variables_code = (VARIABLE_CODE % PiwikVar(*var)._asdict()
for var in complete_variables)
userid = get_identity(context, 'piwik')
if userid is not None:
variables_code = chain(variables_code, (
IDENTITY_CODE % {'userid': userid},
))
html = TRACKING_CODE % {
'url': self.domain_path,
'siteid': self.site_id,
'variables': '\n '.join(variables_code)
}
if is_internal_ip(context, 'PIWIK'):
html = disable_html(html, 'Piwik')
return html
def contribute_to_analytical(add_node):
PiwikNode() # ensure properly configured
add_node('body_bottom', PiwikNode)