This commit is contained in:
Matthew Amstutz 2022-08-05 17:50:02 +00:00 committed by GitHub
commit 028b40a19b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 127 additions and 6 deletions

View 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': ""}

View file

@ -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

View file

@ -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