mirror of
https://github.com/jazzband/django-analytical.git
synced 2026-05-22 14:02:01 +00:00
Merge b4611da6d3 into 6e367cdd2d
This commit is contained in:
commit
028b40a19b
3 changed files with 127 additions and 6 deletions
31
analytical/context_providers/matomo.py
Normal file
31
analytical/context_providers/matomo.py
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import utils
|
||||
from django.conf import settings
|
||||
|
||||
def consent_provider(request):
|
||||
"""
|
||||
Add Mamoto consent script to the requests context.
|
||||
"""
|
||||
# Do we require consent?
|
||||
if getattr(settings, 'MATOMO_REQUIRE_CONSENT', False):
|
||||
provide_script = True
|
||||
if request.user.is_authenticated and not getattr(settings, "ALWAYS_TRACK_REGISTERED", True):
|
||||
provide_script = False
|
||||
if provide_script:
|
||||
grant_class_name = getattr(settings, 'GRANT_CONSENT_TAG_CLASSNAME')
|
||||
revoke_class_name = getattr(settings, 'REVOKE_CONSENT_CLASSNAME')
|
||||
return {"consent_script":"""
|
||||
%s;
|
||||
%s
|
||||
%s
|
||||
""" % (
|
||||
utils.build_paq_cmd('requireConsent'),
|
||||
utils.get_event_bind_js(
|
||||
class_name=grant_class_name,
|
||||
matomo_event="rememberConsentGiven",
|
||||
),
|
||||
utils.get_event_bind_js(
|
||||
class_name=revoke_class_name,
|
||||
matomo_event="forgetConsentGiven",
|
||||
)
|
||||
)}
|
||||
return {'consent_script': ""}
|
||||
|
|
@ -7,13 +7,12 @@ from collections import namedtuple
|
|||
from itertools import chain
|
||||
|
||||
from django.conf import settings
|
||||
from django.template import Library, Node, TemplateSyntaxError
|
||||
|
||||
from django.template import Library, Node, TemplateSyntaxError, Template
|
||||
from analytical.utils import (
|
||||
disable_html,
|
||||
get_identity,
|
||||
get_required_setting,
|
||||
is_internal_ip,
|
||||
is_internal_ip
|
||||
)
|
||||
|
||||
# domain name (characters separated by a dot), optional port, optional URI path, no slash
|
||||
|
|
@ -48,10 +47,8 @@ DEFAULT_SCOPE = 'page'
|
|||
|
||||
MatomoVar = namedtuple('MatomoVar', ('index', 'name', 'value', 'scope'))
|
||||
|
||||
|
||||
register = Library()
|
||||
|
||||
|
||||
@register.tag
|
||||
def matomo(parser, token):
|
||||
"""
|
||||
|
|
@ -109,8 +106,14 @@ class MatomoNode(Node):
|
|||
'variables': '\n '.join(variables_code),
|
||||
'commands': '\n '.join(commands)
|
||||
}
|
||||
# Force the consent script to render so we can inject it into the template
|
||||
consent_script = Template("{{consent_script}}").render(context)
|
||||
if len(consent_script) > 1:
|
||||
html += consent_script
|
||||
|
||||
if is_internal_ip(context, 'MATOMO'):
|
||||
html = disable_html(html, 'Matomo')
|
||||
|
||||
return html
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
"""
|
||||
Utility function for django-analytical.
|
||||
"""
|
||||
|
||||
from copy import deepcopy
|
||||
from django.conf import settings
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
|
||||
|
|
@ -163,3 +163,90 @@ class AnalyticalException(Exception):
|
|||
be silenced in templates.
|
||||
"""
|
||||
silent_variable_failure = True
|
||||
|
||||
def build_paq_cmd(cmd, args=[]):
|
||||
"""
|
||||
:Args:
|
||||
- cmd: The command to be pushed to paq (i.e enableHeartbeatTimer or contentInteraction)
|
||||
- args: Arguments to be added to the paq command. This is mainly
|
||||
used when building commands to be used on manual event trigger.
|
||||
|
||||
:Returns:
|
||||
A complete '_paq.push([])' command in string form
|
||||
"""
|
||||
def __to_js_arg(arg):
|
||||
"""
|
||||
Turn 'arg' into its javascript counter-part
|
||||
:Args:
|
||||
- arg: the argument that's to be passed to the array in _paq.push()
|
||||
:Return:
|
||||
The javascript counter-part to the argument that was passed
|
||||
"""
|
||||
if isinstance(arg, dict):
|
||||
arg_cpy = deepcopy(arg)
|
||||
for k, v in arg_cpy.items():
|
||||
arg.pop(k)
|
||||
arg[__to_js_arg(k)] = __to_js_arg(v)
|
||||
return arg
|
||||
elif isinstance(arg, bool):
|
||||
if arg:
|
||||
arg = "true"
|
||||
else:
|
||||
arg = "false"
|
||||
elif isinstance(arg, list):
|
||||
for elem_idx in range(len(arg)):
|
||||
arg[elem_idx] = __to_js_arg(arg[elem_idx])
|
||||
|
||||
return arg
|
||||
|
||||
paq = "_paq.push(['%s'" % (cmd)
|
||||
if len(args) > 0:
|
||||
paq += ", "
|
||||
for arg_idx in range(len(args)):
|
||||
current_arg = __to_js_arg(args[arg_idx])
|
||||
no_quotes = type(current_arg) in [bool, int, dict, list]
|
||||
if arg_idx == len(args)-1:
|
||||
if no_quotes:
|
||||
segment = "%s]);" % (current_arg)
|
||||
else:
|
||||
segment = "'%s']);" % (current_arg)
|
||||
else:
|
||||
if no_quotes:
|
||||
segment = "%s, "% (current_arg)
|
||||
else:
|
||||
segment = "'%s', " % (current_arg)
|
||||
paq += segment
|
||||
else:
|
||||
paq += "]);"
|
||||
return paq
|
||||
|
||||
def get_event_bind_js(
|
||||
class_name, matomo_event,
|
||||
matomo_args=[], js_event="onclick",
|
||||
):
|
||||
"""
|
||||
Build a javascript command to bind an onClick event to some
|
||||
element whose handler pushes something to _paq
|
||||
:Args:
|
||||
- class_name: Value of the 'class' attribute of the tag
|
||||
the event is to be bound to.
|
||||
- matomo_event: The matomo event to be pushed to _paq
|
||||
such as enableHeartbeatTimer or contentInteraction
|
||||
- matomo_args: The arguments to be passed with the matomo event
|
||||
meaning
|
||||
:Return:
|
||||
A string of javascript that loops the elements found by
|
||||
document.getElementByClassName and binds the motomo event
|
||||
to each element that was found
|
||||
"""
|
||||
script = f"""
|
||||
var elems = document.getElementByClassName('%s');
|
||||
for (var i=0; i++; i < elems.length){{
|
||||
elems[i].addEventListener('%s',
|
||||
function(){{
|
||||
%s;
|
||||
}}
|
||||
);
|
||||
}}
|
||||
""" % (class_name, js_event, build_paq_cmd(matomo_event, matomo_args))
|
||||
return script
|
||||
|
|
|
|||
Loading…
Reference in a new issue