-
-
Notifications
You must be signed in to change notification settings - Fork 168
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix #141 and add custom event trigger binding support #193
Conversation
Added tracking support
Added paq builder function and function to build javascript for binding events
Added missing new end line
@bittner would you mind looking over this PR? It's pretty simple but can expose some extra options for the users of the package |
Update `utils.build_paq_cmd()` to convert all elements in the args list to their javascript counter-parts. This will recursively convert the keys and values of a dictionary until there are no more nested dictionaries and will also convert all the elements of a list as well. Also made it so things like booleans, lists, and dictionaries are not surrounded in quotation marks so they're treated like a normal javascript object. If that behavior needs changed. Please let me know
Updated to use the tested and better documented version (Is not tested with Matomo or Django. Only with python)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is kind of important considering it can possibly break the code.
Modified utils.build_paq_cmd to remove the trailing comma and white space as well as add a semi colon to the end of the push command. Added context_providers directory with matomo.py file with a context provider that builds the tracking consent code and adds it to the context. Modified matomo.MatomoNode.render. Removed original ugly settings check code with simply rendering the 'consent_script' context variable and adding it to the html variable only if its length is greater than 1. NOTE: The context provider and rendering it (line 110 templatetags/matomo.py) are untested. Both utils.build_paq_cmd and utils.get_event_bind_js are tested but need need more rigorous testing to be sure it won't break.
Renamed context provider to 'consent_provider' to make more sense when adding it to your context_provider
@bittner This seems ready, would you mind looking it over? |
|
Removed a random note I forgot to take out
I actuallly don't see that; I thought not having hard coded chunks of JS would be best. I figured dynamically creating the javascript for event binding could let people trigger custom events as well as keep the files relatively free of chunks of hard coded javascript. So, it just made sense to add them in and since I already had the code it made no sense to hard code the JS when what I already wrote makes doing so completely obsolete (for event binding and paq commands anyway). It may take me a minute to figure out how to properly write tests for this. I'll dig in on my next break from my current project. Squashing the changes means using When it comes to splitting up the PRs, from what I understand and, forgive me if I'm misunderstanding, I need to rebase all of the changes out, take out the functions I added in analytics/utils.py then just hardcode the javascript into the context provider? Then on a separate PR introduce the two utility functions again? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I left a few style comments.
More than that, there are no tests for your code. Please add some!
# Do we require consent? | ||
if getattr(settings, 'MATOMO_REQUIRE_CONSENT', False): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about using a self-explanatory variable instead of a comment? e.g.
# Do we require consent? | |
if getattr(settings, 'MATOMO_REQUIRE_CONSENT', False): | |
consent_required = getattr(settings, 'MATOMO_REQUIRE_CONSENT', False) | |
if consent_required: |
provide_script = True | ||
if request.user.is_authenticated and not getattr(settings, "ALWAYS_TRACK_REGISTERED", True): | ||
provide_script = False |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could be make more readable by using another self-explanatory variable, e.g.
provide_script = True | |
if request.user.is_authenticated and not getattr(settings, "ALWAYS_TRACK_REGISTERED", True): | |
provide_script = False | |
always_track = getattr(settings, "ALWAYS_TRACK_REGISTERED", True) | |
provide_script = not request.user.is_authenticated or always_track |
if provide_script: | ||
grant_class_name = getattr(settings, 'GRANT_CONSENT_TAG_CLASSNAME') | ||
revoke_class_name = getattr(settings, 'REVOKE_CONSENT_CLASSNAME') | ||
return {"consent_script":""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return {"consent_script":""" | |
return {"consent_script": """ |
Flake8 will complain otherwise, I believe.
from analytical.utils import ( | ||
disable_html, | ||
get_identity, | ||
get_required_setting, | ||
is_internal_ip, | ||
is_internal_ip |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would suggest to leave the trailing comma here. That makes subsequent git diffs more obvious.
@@ -109,8 +106,14 @@ def render(self, context): | |||
'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: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if len(consent_script) > 1: | |
if consent_script: |
... would be more pythonic.
In this case, though, the consent_script
really needs to have a zero-length or no value (""
or None
). I guess that's the case.
|
||
return arg | ||
|
||
paq = "_paq.push(['%s'" % (cmd) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Round braces are not required with a single argument:
paq = "_paq.push(['%s'" % (cmd) | |
paq = "_paq.push(['%s'" % cmd |
paq = "_paq.push(['%s'" % (cmd) | ||
if len(args) > 0: | ||
paq += ", " | ||
for arg_idx in range(len(args)): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please make this pythonic, e.g.
for arg_idx in range(len(args)): | |
for item in args: |
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) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why don't you simply add the quotes around the current_arg
value before the entire block? Then none of those if
clauses are needed. Example:
current_arg = current_arg if no_quotes else "'%s'" % current_arg
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: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is – and the else
black below – is not an elegant solution. Why don't you simply always add the ", "
and replace it by "]);"
after the end of the loop? e.g.
paq = paq[:-3)] + "]);"
return paq
def get_event_bind_js( | ||
class_name, matomo_event, | ||
matomo_args=[], js_event="onclick", | ||
): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
def get_event_bind_js( | |
class_name, matomo_event, | |
matomo_args=[], js_event="onclick", | |
): | |
def get_event_bind_js( | |
class_name, matomo_event, matomo_args=[], js_event="onclick" | |
): |
Take a look at the tests that are there. The idea is simple:
That's it. If there are various possible outcomes for different input, add more of those calls with different input, so that all of your |
This should work to make Matomo respect consent.
I created two new utility functions, one builds paq commands, the other builds javascript to bind an event listener to elements with a certain class name. That will allow users to make their own custom template tags then use
analytical.utils.get_event_bind_js()
to bind events to their elements.