Add Performable service. Update docs layout.

Use included README.rst in documentation.  Bump version to 0.3.0.
This commit is contained in:
Joost Cassee 2011-01-31 08:57:26 +01:00
parent e3a652766b
commit 6ea7e85b02
14 changed files with 326 additions and 54 deletions

View file

@ -1,5 +1,5 @@
Development
-----------
Version 0.3.0
-------------
* Added support for the Performable service.
Version 0.2.0

View file

@ -1,2 +1,2 @@
include LICENSE.txt
include LICENSE.txt *.rst
recursive-include docs *.rst *.py

View file

@ -1,5 +1,5 @@
django-analytical
-----------------
=================
The django-analytical application integrates analytics services into a
Django_ project.
@ -8,6 +8,7 @@ Using an analytics service with a Django project means adding Javascript
tracking code to the project templates. Of course, every service has
its own specific installation instructions. Furthermore, you need to
include your unique identifiers, which then end up in the templates.
This application hides the details of the different analytics services
behind a generic interface, and keeps personal information and
configuration out of the templates. Its goal is to make the basic
@ -30,12 +31,12 @@ Currently supported services:
The documentation can be found in the ``docs`` directory or `read
online`_. The project source is `hosted by GitHub`_.
If you want to help out with development of django-analytical, by
posting detailed bug reports, suggesting new features or other analytics
services to support, or doing some development work yourself, please use
the `issue tracker`_. If you want to get your hands dirty yourself,
great! Clone the repository, make changes and send a pull request.
Please do create an issue to discuss your plans.
If you want to help out with the development of django-analytical, by
posting detailed bug reports, proposing new features or other analytics
services to support, or suggesting documentation improvements, use the
`issue tracker`_. If you want to get your hands dirty, great! Clone
the repository, make changes and send a pull request. Please do create
an issue to discuss your plans.
.. _Django: http://www.djangoproject.com/
.. _Chartbeat: http://www.chartbeat.com/

View file

@ -10,6 +10,6 @@ Django_ project. See the ``docs`` directory for more information.
__author__ = "Joost Cassee"
__email__ = "joost@cassee.net"
__version__ = "0.2.0"
__version__ = "0.3.0"
__copyright__ = "Copyright (C) 2011 Joost Cassee"
__license__ = "MIT License"

View file

@ -0,0 +1,77 @@
"""
Performable template tags and filters.
"""
from __future__ import absolute_import
import re
from django.template import Library, Node, TemplateSyntaxError
from analytical.utils import is_internal_ip, disable_html, get_identity, \
get_required_setting
API_KEY_RE = re.compile(r'^\w{6}$')
SETUP_CODE = """<script src="//d1nu2rn22elx8m.cloudfront.net/performable/pax/%(api_key)s.js" type="text/javascript"></script>"""
IDENTIFY_CODE = """
<script type="text/javascript">
var _paq = _paq || [];
_paq.push(["identify", {identity: "%s"}]);
</script>
"""
EMBED_CODE = """
<script type="text/javascript" src="//d1nu2rn22elx8m.cloudfront.net/performable/embed/page.js"></script>
<script type="text/javascript">
(function() {
var $f = new PerformableEmbed();
$f.initialize({'host': '%(hostname)s', 'page': '%(page_id)s'});
$f.write();
})()
</script>
"""
register = Library()
@register.tag
def performable(parser, token):
"""
Performable template tag.
Renders Javascript code to set-up Performable tracking. You must
supply your Performable API key in the ``PERFORMABLE_API_KEY``
setting.
"""
bits = token.split_contents()
if len(bits) > 1:
raise TemplateSyntaxError("'%s' takes no arguments" % bits[0])
return PerformableNode()
class PerformableNode(Node):
def __init__(self):
self.api_key = get_required_setting(
'PERFORMABLE_API_KEY', API_KEY_RE,
"must be a string containing five alphanumerical characters")
def render(self, context):
html = SETUP_CODE % {'api_key': self.api_key}
identity = get_identity(context, 'performable')
if identity is not None:
html = "%s%s" % (IDENTIFY_CODE % identity, html)
if is_internal_ip(context, 'PERFORMABLE'):
html = disable_html(html, 'Performable')
return html
@register.simple_tag
def performable_embed(hostname, page_id):
"""
Include a Performable landing page.
"""
return EMBED_CODE % locals()
def contribute_to_analytical(add_node):
PerformableNode() # ensure properly configured
add_node('body_bottom', PerformableNode)

View file

@ -12,4 +12,5 @@ from analytical.tests.test_tag_kiss_insights import *
from analytical.tests.test_tag_kiss_metrics import *
from analytical.tests.test_tag_mixpanel import *
from analytical.tests.test_tag_optimizely import *
from analytical.tests.test_tag_performable import *
from analytical.tests.test_utils import *

View file

@ -0,0 +1,69 @@
"""
Tests for the Performable template tags and filters.
"""
from django.http import HttpRequest
from django.template import Context
from analytical.templatetags.performable import PerformableNode
from analytical.tests.utils import TagTestCase
from analytical.utils import AnalyticalException
from django.contrib.auth.models import User
class PerformableTagTestCase(TagTestCase):
"""
Tests for the ``performable`` template tag.
"""
def setUp(self):
super(PerformableTagTestCase, self).setUp()
self.settings_manager.set(PERFORMABLE_API_KEY='123ABC')
def test_tag(self):
r = self.render_tag('performable', 'performable')
self.assertTrue('/performable/pax/123ABC.js' in r, r)
def test_node(self):
r = PerformableNode().render(Context())
self.assertTrue('/performable/pax/123ABC.js' in r, r)
def test_no_api_key(self):
self.settings_manager.delete('PERFORMABLE_API_KEY')
self.assertRaises(AnalyticalException, PerformableNode)
def test_wrong_account_number(self):
self.settings_manager.set(PERFORMABLE_API_KEY='123AB')
self.assertRaises(AnalyticalException, PerformableNode)
self.settings_manager.set(PERFORMABLE_API_KEY='123ABCD')
self.assertRaises(AnalyticalException, PerformableNode)
def test_render_internal_ip(self):
self.settings_manager.set(ANALYTICAL_INTERNAL_IPS=['1.1.1.1'])
req = HttpRequest()
req.META['REMOTE_ADDR'] = '1.1.1.1'
context = Context({'request': req})
r = PerformableNode().render(context)
self.assertTrue(r.startswith(
'<!-- Performable disabled on internal IP address'), r)
self.assertTrue(r.endswith('-->'), r)
def test_identify(self):
self.settings_manager.set(ANALYTICAL_AUTO_IDENTIFY=True)
r = PerformableNode().render(Context({'user': User(username='test')}))
self.assertTrue('_paq.push(["identify", {identity: "test"}]);' in r, r)
class PerformableEmbedTagTestCase(TagTestCase):
"""
Tests for the ``performable_embed`` template tag.
"""
def test_tag(self):
d = 'example.com'
p = 'test'
r = self.render_tag('performable', 'performable_embed "%s" "%s"'
% (d, p))
self.assertTrue(
"$f.initialize({'host': 'example.com', 'page': 'test'});" in r,
r)

View file

@ -26,11 +26,5 @@ Credits
Helping out
===========
If you want to help out with development of django-analytical, by
posting detailed bug reports, suggesting new features or other analytics
services to support, or doing some development work yourself, please use
the `issue tracker`_. If you want to get your hands dirty yourself,
great! Clone the repository, make changes and send a pull request.
Please do create an issue to discuss your plans.
.. _`issue tracker`: http://github.com/jcassee/django-analytical/issues
.. include:: ../README.rst
:start-line: 32

View file

@ -1,9 +1,9 @@
========================================
Analytics service integration for Django
========================================
=================
django-analytical
=================
The django-analytical application integrates various analytics services
into a Django_ project.
The django-analytical application integrates analytics services into a
Django_ project.
.. _Django: http://www.djangoproject.com/
@ -14,17 +14,9 @@ into a Django_ project.
Overview
========
If your want to integrating an analytics service into a Django project,
you need to add Javascript tracking code to the project templates.
Of course, every service has its own specific installation instructions.
Furthermore, you need to include your unique identifiers, which then end
up in the templates. This application hides the details of the
different analytics services behind a generic interface, and keeps
personal information and configuration out of the templates. Its goal
is to make basic usage set-up very simple, while allowing advanced users
to customize tracking. Each service is set up as recommended by the
services themselves, using an asynchronous version of the Javascript
code if possible.
.. include:: ../README.rst
:start-line: 6
:end-line: 17
To get a feel of how django-analytics works, check out the
:doc:`tutorial`.

View file

@ -51,13 +51,13 @@ portal ID and domain.
Setting the portal ID and domain
--------------------------------
Your HubSpot account has its own portal ID and primary websit, and the
:ttag:`hubspot` tag will include them in the rendered Javascript code.
You can find the portal ID and domain by going to the *Domains* tab in
your HubSpot account. The domain you need to use is listed as *Primary
Domain* on that page, and the portal ID can be found in the footer. Set
:const:`HUBSPOT_PORTAL_ID` and :const:`HUBSPOT_DOMAIN` in the
project :file:`settings.py` file::
Your HubSpot account has its own portal ID and primary domain name, and
the :ttag:`hubspot` tag will include them in the rendered Javascript
code. You can find the portal ID and domain by going to the *Domains*
tab in your HubSpot account. The domain you need to use is listed as
*Primary Domain* on that page, and the portal ID can be found in the
footer. Set :const:`HUBSPOT_PORTAL_ID` and :const:`HUBSPOT_DOMAIN` in
the project :file:`settings.py` file::
HUBSPOT_PORTAL_ID = 'XXXX'
HUBSPOT_DOMAIN = 'XXXXXXXX.web101.hubspot.com'

View file

@ -26,9 +26,9 @@ This step is only needed if you are not using the generic
:ref:`optimizely-configuration`.
The Optimizely Javascript code is inserted into templates using a
template tag. Load the :mod:`mixpanel` template tag library and insert
the :ttag:`optimizely` tag. Because every page that you want to track
must have the tag, it is useful to add it to your base template.
template tag. Load the :mod:`optimizely` template tag library and
insert the :ttag:`optimizely` 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 top of the HTML head::
{% load optimizely %}
@ -54,7 +54,7 @@ Setting the account number
Optimizely gives you a unique account number, and the :ttag:`optimizely`
tag will include it in the rendered Javascript code. You can find your
account number by clicking the `Implementation` link in the top
account number by clicking the *Implementation* link in the top
right-hand corner of the Optimizely website. A pop-up window will
appear containing HTML code looking like this::

View file

@ -0,0 +1,133 @@
==============================================
Performable -- web analytics and landing pages
==============================================
Performable_ provides a platform for inbound marketing, landing pages
and web analytics. Its analytics module tracks individual customer
interaction, funnel and e-commerce analysis. Landing pages can be
created and designed on-line, and integrated with you existing website.
.. _Performable: http://www.performable.com/
.. performable-installation:
Installation
============
To start using the Performable 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 Performable template tags to your templates.
This step is only needed if you are not using the generic
:ttag:`analytical.*` tags. If you are, skip to
:ref:`performable-configuration`.
The Performable Javascript code is inserted into templates using a
template tag. Load the :mod:`performable` template tag library and
insert the :ttag:`performable` 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::
{% load performable %}
...
{% performable %}
</body>
</html>
.. _performable-configuration:
Configuration
=============
Before you can use the Performable integration, you must first set your
API key.
.. _performable-account-code:
Setting the API key
-------------------
You Performable account has its own API key, which :ttag:`performable`
tag will include it in the rendered Javascript code. You can find your
API key on the *Account Settings* page (click 'Account Settings' in the
top right-hand corner of your Performable dashboard. Set
:const:`PERFORMABLE_API_KEY` in the project :file:`settings.py` file::
PERFORMABLE_API_KEY = 'XXXXXX'
If you do not set an API key, the Javascript code will not be rendered.
.. _performable-identity-user:
Identifying authenticated users
-------------------------------
If your websites identifies visitors, you can pass this information on
to Performable so that you can tie survey submissions to customers.
By default, the username of an authenticated user is passed to
Performable automatically. See :ref:`identifying-visitors`.
You can also send the visitor identity yourself by adding either the
``performable_identity`` or the ``analytical_identity`` variable to
the template context. If both variables are set, the former takes
precedence. For example::
context = RequestContext({'performable_identity': identity})
return some_template.render(context)
If you can derive the identity from the HTTP request, you can also use
a context processor that you add to the
:data:`TEMPLATE_CONTEXT_PROCESSORS` list in :file:`settings.py`::
def identify(request):
try:
return {'performable_identity': request.user.email}
except AttributeError:
return {}
Just remember that if you set the same context variable in the
:class:`~django.template.context.RequestContext` constructor and in a
context processor, the latter clobbers the former.
.. _performable-internal-ips:
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:`PERFORMABLE_INTERNAL_IPS` setting,
the tracking code is commented out. It takes the value of
:const:`ANALYTICAL_INTERNAL_IPS` by default (which in turn is
:const:`INTERNAL_IPS` by default). See :ref:`identifying-visitors` for
important information about detecting the visitor IP address.
.. _performable-embed-page:
Embedding a landing page
========================
You can embed a Performable landing page in your Django website. The
:ttag:`performable_embed` template tag adds the Javascript code to embed
the page. It takes two arguments: the hostname and the page ID::
{% performable_embed HOSTNAME PAGE_ID %}
To find the hostname and page ID, select :menuselection:`Manage -->
Manage Landing Pages` on your Performable dashboard. Select the landing
page you want to embed. Look at the URL in your browser address bar; it
will look like this::
http://my.performable.com/s/HOSTNAME/page/PAGE_ID/
(If you are placing the hostname and page id values in the template, do
not forget to enclose them in quotes or they will be considered context
variable names.)

View file

@ -9,16 +9,20 @@ their default values.
.. data:: ANALYTICAL_AUTO_IDENTIFY
Default: ``True``
Default: ``True``
Automatically identify logged in users by their username. See
:ref:`identifying-visitors`.
Automatically identify logged in users by their username. See
:ref:`identifying-visitors`.
.. data:: ANALYTICAL_INTERNAL_IPS
Default: :data:`INTERNAL_IPS`
Default: :data:`INTERNAL_IPS`
A list or tuple of internal IP addresses. Tracking code will be
commented out for visitors from any of these addresses. See
:ref:`internal-ips`.
A list or tuple of internal IP addresses. Tracking code will be
commented out for visitors from any of these addresses. You can
configure this setting for each service individually by substituting
``ANALYTICAL`` for the upper-case service name. For example, set
``GOOGLE_ANALYTICS_INTERNAL_IPS`` to configure for Google Analytics.
See :ref:`internal-ips`.

View file

@ -43,7 +43,7 @@ setup(
name = 'django-analytical',
version = analytical.__version__,
license = analytical.__license__,
description = 'Analytics services for Django projects',
description = 'Analytics service integration for Django projects',
long_description = read('README.rst'),
author = analytical.__author__,
author_email = analytical.__email__,
@ -51,6 +51,7 @@ setup(
'analytical',
'analytical.templatetags',
'analytical.tests',
'analytical.tests.templatetags',
],
keywords = ['django', 'analytics'],
classifiers = [