Remove deprecated Piwik integration

Please use our Matomo integration instead
This commit is contained in:
Peter Bittner 2022-07-01 00:50:12 +02:00
parent ba59f396df
commit 688524305f
6 changed files with 4 additions and 460 deletions

View file

@ -1,3 +1,7 @@
Unreleased
----------
* Remove deprecated Piwik integration. Use Matomo instead! (Peter Bittner)
Version 3.1.0
-------------
* Rename default branch from master to main (Peter Bittner, Jannis Leidel)

View file

@ -35,7 +35,6 @@ TAG_MODULES = [
'analytical.olark',
'analytical.optimizely',
'analytical.performable',
'analytical.piwik',
'analytical.rating_mailru',
'analytical.snapengage',
'analytical.spring_metrics',

View file

@ -1,121 +0,0 @@
"""
Piwik template tags and filters.
"""
import re
import warnings
from collections import namedtuple
from itertools import chain
from django.conf import settings
from django.template import Library, Node, TemplateSyntaxError
from analytical.utils import (
disable_html,
get_identity,
get_required_setting,
is_internal_ip,
)
# 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
%(commands)s
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function() {
var u="//%(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.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s);
})();
</script>
<noscript><p><img src="//%(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"]);'
DISABLE_COOKIES_CODE = '_paq.push([\'disableCookies\']);'
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.
"""
warnings.warn('The Piwik module is deprecated; use the Matomo module.', DeprecationWarning)
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)
commands = []
if getattr(settings, 'PIWIK_DISABLE_COOKIES', False):
commands.append(DISABLE_COOKIES_CODE)
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),
'commands': '\n '.join(commands)
}
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)

View file

@ -188,11 +188,6 @@ settings required to enable each service are listed here:
PERFORMABLE_API_KEY = '123abc'
* :doc:`Piwik (deprecated, see Matomo) <services/piwik>`::
PIWIK_DOMAIN_PATH = 'your.piwik.server/optional/path'
PIWIK_SITE_ID = '123'
* :doc:`Rating\@Mail.ru <services/rating_mailru>`::
RATING_MAILRU_COUNTER_ID = '1234567'

View file

@ -1,179 +0,0 @@
==================================
Piwik (deprecated) -- open source web analytics
==================================
Piwik_ is an open analytics platform currently used by individuals,
companies and governments all over the world. With Piwik, your data
will always be yours, because you run your own analytics server.
.. _Piwik: http://www.piwik.org/
Deprecated
==========
Note that Piwik is now known as Matomo. New projects should use the
Matomo integration. The Piwik integration in django-analytical is
deprecated and eventually will be removed.
Installation
============
To start using the Piwik integration, you must have installed the
django-analytical package and have added the ``analytical`` application
to :const:`INSTALLED_APPS` in your project :file:`settings.py` file.
See :doc:`../install` for details.
Next you need to add the Piwik template tag to your templates. This
step is only needed if you are not using the generic
:ttag:`analytical.*` tags. If you are, skip to
:ref:`piwik-configuration`.
The Piwik tracking code is inserted into templates using a template
tag. Load the :mod:`piwik` template tag library and insert the
:ttag:`piwik` tag. Because every page that you want to track must
have the tag, it is useful to add it to your base template. Insert
the tag at the bottom of the HTML body as recommended by the
`Piwik best practice for Integration Plugins`_::
{% load piwik %}
...
{% piwik %}
</body>
</html>
.. _`Piwik best practice for Integration Plugins`: http://piwik.org/integrate/how-to/
.. _piwik-configuration:
Configuration
=============
Before you can use the Piwik integration, you must first define
domain name and optional URI path to your Piwik server, as well as
the Piwik ID of the website you're tracking with your Piwik server,
in your project settings.
Setting the domain
------------------
Your Django project needs to know where your Piwik server is located.
Typically, you'll have Piwik installed on a subdomain of its own
(e.g. ``piwik.example.com``), otherwise it runs in a subdirectory of
a website of yours (e.g. ``www.example.com/piwik``). Set
:const:`PIWIK_DOMAIN_PATH` in the project :file:`settings.py` file
accordingly::
PIWIK_DOMAIN_PATH = 'piwik.example.com'
If you do not set a domain the tracking code will not be rendered.
Setting the site ID
-------------------
Your Piwik server can track several websites. Each website has its
site ID (this is the ``idSite`` parameter in the query string of your
browser's address bar when you visit the Piwik Dashboard). Set
:const:`PIWIK_SITE_ID` in the project :file:`settings.py` file to
the value corresponding to the website you're tracking::
PIWIK_SITE_ID = '4'
If you do not set the site ID the tracking code will not be rendered.
.. _piwik-uservars:
User variables
--------------
Piwik supports sending `custom variables`_ along with default statistics. If
you want to set a custom variable, use the context variable ``piwik_vars`` when
you render your template. It should be an iterable of custom variables
represented by 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. ::
context = Context({
'piwik_vars': [(1, 'foo', 'Sir Lancelot of Camelot'),
(2, 'bar', 'To seek the Holy Grail', 'page'),
(3, 'spam', 'Blue', 'visit')]
})
return some_template.render(context)
Piwik default settings allow up to 5 custom variables for both scope. Variable
mapping between index and name must stay constant, or the latest name
override the previous one.
If you use the same user variables in different views and its value can
be computed from the HTTP request, you can also set them in a context
processor that you add to the :data:`TEMPLATE_CONTEXT_PROCESSORS` list
in :file:`settings.py`.
.. _`custom variables`: http://developer.piwik.org/guides/tracking-javascript-guide#custom-variables
.. _piwik-user-tracking:
User tracking
-------------
If you use the standard Django authentication system, you can allow Piwik to
`track individual users`_ by setting the :data:`ANALYTICAL_AUTO_IDENTIFY`
setting to :const:`True`. This is enabled by default. Piwik will identify
users based on their ``username``.
If you disable this settings, or want to customize what user id to use, you can
set the context variable ``analytical_identity`` (for global configuration) or
``piwik_identity`` (for Piwik specific configuration). Setting one to
:const:`None` will disable the user tracking feature::
# Piwik will identify this user as 'BDFL' if ANALYTICAL_AUTO_IDENTIFY is True or unset
request.user = User(username='BDFL', first_name='Guido', last_name='van Rossum')
# Piwik will identify this user as 'Guido van Rossum'
request.user = User(username='BDFL', first_name='Guido', last_name='van Rossum')
context = Context({
'piwik_identity': request.user.get_full_name()
})
# Piwik will not identify this user (but will still collect statistics)
request.user = User(username='BDFL', first_name='Guido', last_name='van Rossum')
context = Context({
'piwik_identity': None
})
.. _`track individual users`: http://developer.piwik.org/guides/tracking-javascript-guide#user-id
Disabling cookies
-----------------
If you want to `disable cookies`_, set :data:`PIWIKI_DISABLE_COOKIES` to
:const:`True`. This is disabled by default.
.. _`disable cookies`: https://matomo.org/faq/general/faq_157/
Internal IP addresses
---------------------
Usually, you do not want to track clicks from your development or
internal IP addresses. By default, if the tags detect that the client
comes from any address in the :const:`ANALYTICAL_INTERNAL_IPS` (which
takes the value of :const:`INTERNAL_IPS` by default) the tracking code
is commented out. See :ref:`identifying-visitors` for important
information about detecting the visitor IP address.
----
Thanks go to Piwik for providing an excellent web analytics platform
entirely for free! Consider donating_ to ensure that they continue
their development efforts in the spirit of open source and freedom
for our personal data.
.. _donating: http://piwik.org/donate/

View file

@ -1,154 +0,0 @@
"""
Tests for the Piwik template tags and filters.
"""
import pytest
from django.contrib.auth.models import User
from django.http import HttpRequest
from django.template import Context
from django.test.utils import override_settings
from utils import TagTestCase
from analytical.templatetags.piwik import PiwikNode
from analytical.utils import AnalyticalException
@override_settings(PIWIK_DOMAIN_PATH='example.com', PIWIK_SITE_ID='345')
class PiwikTagTestCase(TagTestCase):
"""
Tests for the ``piwik`` template tag.
"""
def test_tag(self):
r = self.render_tag('piwik', 'piwik')
assert '"//example.com/"' in r
assert "_paq.push(['setSiteId', 345]);" in r
assert 'img src="//example.com/piwik.php?idsite=345"' in r
def test_node(self):
r = PiwikNode().render(Context({}))
assert '"//example.com/";' in r
assert "_paq.push(['setSiteId', 345]);" in r
assert 'img src="//example.com/piwik.php?idsite=345"' in r
@override_settings(PIWIK_DOMAIN_PATH='example.com/piwik',
PIWIK_SITE_ID='345')
def test_domain_path_valid(self):
r = self.render_tag('piwik', 'piwik')
assert '"//example.com/piwik/"' in r
@override_settings(PIWIK_DOMAIN_PATH='example.com:1234',
PIWIK_SITE_ID='345')
def test_domain_port_valid(self):
r = self.render_tag('piwik', 'piwik')
assert '"//example.com:1234/";' in r
@override_settings(PIWIK_DOMAIN_PATH='example.com:1234/piwik',
PIWIK_SITE_ID='345')
def test_domain_port_path_valid(self):
r = self.render_tag('piwik', 'piwik')
assert '"//example.com:1234/piwik/"' in r
@override_settings(PIWIK_DOMAIN_PATH=None)
def test_no_domain(self):
with pytest.raises(AnalyticalException):
PiwikNode()
@override_settings(PIWIK_SITE_ID=None)
def test_no_siteid(self):
with pytest.raises(AnalyticalException):
PiwikNode()
@override_settings(PIWIK_SITE_ID='x')
def test_siteid_not_a_number(self):
with pytest.raises(AnalyticalException):
PiwikNode()
@override_settings(PIWIK_DOMAIN_PATH='http://www.example.com')
def test_domain_protocol_invalid(self):
with pytest.raises(AnalyticalException):
PiwikNode()
@override_settings(PIWIK_DOMAIN_PATH='example.com/')
def test_domain_slash_invalid(self):
with pytest.raises(AnalyticalException):
PiwikNode()
@override_settings(PIWIK_DOMAIN_PATH='example.com:123:456')
def test_domain_multi_port(self):
with pytest.raises(AnalyticalException):
PiwikNode()
@override_settings(PIWIK_DOMAIN_PATH='example.com:')
def test_domain_incomplete_port(self):
with pytest.raises(AnalyticalException):
PiwikNode()
@override_settings(PIWIK_DOMAIN_PATH='example.com:/piwik')
def test_domain_uri_incomplete_port(self):
with pytest.raises(AnalyticalException):
PiwikNode()
@override_settings(PIWIK_DOMAIN_PATH='example.com:12df')
def test_domain_port_invalid(self):
with pytest.raises(AnalyticalException):
PiwikNode()
@override_settings(ANALYTICAL_INTERNAL_IPS=['1.1.1.1'])
def test_render_internal_ip(self):
req = HttpRequest()
req.META['REMOTE_ADDR'] = '1.1.1.1'
context = Context({'request': req})
r = PiwikNode().render(context)
assert r.startswith('<!-- Piwik disabled on internal IP address')
assert r.endswith('-->')
def test_uservars(self):
context = Context({'piwik_vars': [(1, 'foo', 'foo_val'),
(2, 'bar', 'bar_val', 'page'),
(3, 'spam', 'spam_val', 'visit')]})
r = PiwikNode().render(context)
for var_code in ['_paq.push(["setCustomVariable", 1, "foo", "foo_val", "page"]);',
'_paq.push(["setCustomVariable", 2, "bar", "bar_val", "page"]);',
'_paq.push(["setCustomVariable", 3, "spam", "spam_val", "visit"]);']:
assert var_code in r
@override_settings(ANALYTICAL_AUTO_IDENTIFY=True)
def test_default_usertrack(self):
context = Context({
'user': User(username='BDFL', first_name='Guido', last_name='van Rossum')
})
r = PiwikNode().render(context)
var_code = '_paq.push(["setUserId", "BDFL"]);'
assert var_code in r
def test_piwik_usertrack(self):
context = Context({
'piwik_identity': 'BDFL'
})
r = PiwikNode().render(context)
var_code = '_paq.push(["setUserId", "BDFL"]);'
assert var_code in r
def test_analytical_usertrack(self):
context = Context({
'analytical_identity': 'BDFL'
})
r = PiwikNode().render(context)
var_code = '_paq.push(["setUserId", "BDFL"]);'
assert var_code in r
@override_settings(ANALYTICAL_AUTO_IDENTIFY=True)
def test_disable_usertrack(self):
context = Context({
'user': User(username='BDFL', first_name='Guido', last_name='van Rossum'),
'piwik_identity': None
})
r = PiwikNode().render(context)
var_code = '_paq.push(["setUserId", "BDFL"]);'
assert var_code not in r
@override_settings(PIWIK_DISABLE_COOKIES=True)
def test_disable_cookies(self):
r = PiwikNode().render(Context({}))
assert "_paq.push(['disableCookies']);" in r