From 4f2d95f9282d1dc658a5c5657c12b4808f85cb20 Mon Sep 17 00:00:00 2001 From: Joost Cassee Date: Thu, 24 Feb 2011 22:20:26 +0100 Subject: [PATCH] Add support for Olark --- README.rst | 2 + analytical/templatetags/olark.py | 76 ++++++++++++++++++ analytical/tests/__init__.py | 1 + analytical/tests/test_tag_olark.py | 61 ++++++++++++++ docs/services/olark.rst | 123 +++++++++++++++++++++++++++++ 5 files changed, 263 insertions(+) create mode 100644 analytical/templatetags/olark.py create mode 100644 analytical/tests/test_tag_olark.py create mode 100644 docs/services/olark.rst diff --git a/README.rst b/README.rst index 8e4bf8c..4fa8d96 100644 --- a/README.rst +++ b/README.rst @@ -27,6 +27,7 @@ Currently supported services: * `KISSinsights`_ feedback surveys * `KISSmetrics`_ funnel analysis * `Mixpanel`_ event tracking +* `Olark`_ visitor chat * `Optimizely`_ A/B testing * `Performable`_ web analytics and landing pages @@ -50,6 +51,7 @@ an issue to discuss your plans. .. _KISSinsights: http://www.kissinsights.com/ .. _KISSmetrics: http://www.kissmetrics.com/ .. _Mixpanel: http://www.mixpanel.com/ +.. _Olark: http://www.olark.com/ .. _Optimizely: http://www.optimizely.com/ .. _Performable: http://www.performable.com/ .. _`read online`: http://packages.python.org/django-analytical/ diff --git a/analytical/templatetags/olark.py b/analytical/templatetags/olark.py new file mode 100644 index 0000000..41eeea1 --- /dev/null +++ b/analytical/templatetags/olark.py @@ -0,0 +1,76 @@ +""" +Olark template tags. +""" + +from __future__ import absolute_import + +import re + +from django.template import Library, Node, TemplateSyntaxError +from django.utils import simplejson + +from analytical.utils import get_identity, get_required_setting + + +SITE_ID_RE = re.compile(r'^\d{4}-\d{3}-\d{2}-\d{4}$') +SETUP_CODE = """ + +""" +NICKNAME_CODE = "olark('api.chat.updateVisitorNickname', {snippet: '%s'});" +NICKNAME_CONTEXT_KEY = 'olark_nickname' +STATUS_CODE = "olark('api.chat.updateVisitorStatus', {snippet: %s});" +STATUS_CONTEXT_KEY = 'olark_status' + + +register = Library() + + +@register.tag +def olark(parser, token): + """ + Olark set-up template tag. + + Renders Javascript code to set-up Olark chat. You must supply + your site ID in the ``OLARK_SITE_ID`` setting. + """ + bits = token.split_contents() + if len(bits) > 1: + raise TemplateSyntaxError("'%s' takes no arguments" % bits[0]) + return OlarkNode() + +class OlarkNode(Node): + def __init__(self): + self.site_id = get_required_setting('OLARK_SITE_ID', SITE_ID_RE, + "must be a string looking like 'XXXX-XXX-XX-XXXX'") + + def render(self, context): + extra_code = [] + try: + extra_code.append(NICKNAME_CODE % context[NICKNAME_CONTEXT_KEY]) + except KeyError: + identity = get_identity(context, 'olark', self._get_nickname) + if identity is not None: + extra_code.append(NICKNAME_CODE % identity) + try: + extra_code.append(STATUS_CODE % + simplejson.dumps(context[STATUS_CONTEXT_KEY])) + except KeyError: + pass + html = SETUP_CODE % {'site_id': self.site_id, + 'extra_code': " ".join(extra_code)} + return html + + def _get_nickname(self, user): + name = user.get_full_name() + if name: + return "%s (%s)" % (name, user.username) + else: + return user.username + + +def contribute_to_analytical(add_node): + OlarkNode() # ensure properly configured + add_node('body_bottom', OlarkNode) diff --git a/analytical/tests/__init__.py b/analytical/tests/__init__.py index d3eb93d..e20af34 100644 --- a/analytical/tests/__init__.py +++ b/analytical/tests/__init__.py @@ -11,6 +11,7 @@ from analytical.tests.test_tag_hubspot import * 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_olark import * from analytical.tests.test_tag_optimizely import * from analytical.tests.test_tag_performable import * from analytical.tests.test_tag_reinvigorate import * diff --git a/analytical/tests/test_tag_olark.py b/analytical/tests/test_tag_olark.py new file mode 100644 index 0000000..494345a --- /dev/null +++ b/analytical/tests/test_tag_olark.py @@ -0,0 +1,61 @@ +""" +Tests for the Olark template tags and filters. +""" + +from django.contrib.auth.models import User +from django.template import Context + +from analytical.templatetags.olark import OlarkNode +from analytical.tests.utils import TagTestCase +from analytical.utils import AnalyticalException + + +class OlarkTestCase(TagTestCase): + """ + Tests for the ``olark`` template tag. + """ + + def setUp(self): + super(OlarkTestCase, self).setUp() + self.settings_manager.set(OLARK_SITE_ID='1234-567-89-0123') + + def test_tag(self): + r = self.render_tag('olark', 'olark') + self.assertTrue("olark.identify('1234-567-89-0123');" in r, r) + + def test_node(self): + r = OlarkNode().render(Context()) + self.assertTrue("olark.identify('1234-567-89-0123');" in r, r) + + def test_no_site_id(self): + self.settings_manager.delete('OLARK_SITE_ID') + self.assertRaises(AnalyticalException, OlarkNode) + + def test_wrong_site_id(self): + self.settings_manager.set(OLARK_SITE_ID='1234-567-89-012') + self.assertRaises(AnalyticalException, OlarkNode) + self.settings_manager.set(OLARK_SITE_ID='1234-567-89-01234') + self.assertRaises(AnalyticalException, OlarkNode) + + def test_identify(self): + self.settings_manager.set(ANALYTICAL_AUTO_IDENTIFY=True) + r = OlarkNode().render(Context({'user': + User(username='test', first_name='Test', last_name='User')})) + self.assertTrue("olark('api.chat.updateVisitorNickname', " + "{snippet: 'Test User (test)'});" in r, r) + + def test_nickname(self): + r = OlarkNode().render(Context({'olark_nickname': 'testnick'})) + self.assertTrue("olark('api.chat.updateVisitorNickname', " + "{snippet: 'testnick'});" in r, r) + + def test_status_string(self): + r = OlarkNode().render(Context({'olark_status': 'teststatus'})) + self.assertTrue("olark('api.chat.updateVisitorStatus', " + '{snippet: "teststatus"});' in r, r) + + def test_status_string_list(self): + r = OlarkNode().render(Context({'olark_status': + ['teststatus1', 'teststatus2']})) + self.assertTrue("olark('api.chat.updateVisitorStatus', " + '{snippet: ["teststatus1", "teststatus2"]});' in r, r) diff --git a/docs/services/olark.rst b/docs/services/olark.rst new file mode 100644 index 0000000..f673e7a --- /dev/null +++ b/docs/services/olark.rst @@ -0,0 +1,123 @@ +===================== +Olark -- visitor chat +===================== + +Olark_ is a lightweight tool to chat with visitors to your website using +your existing instant messaging client. Chat with your website visitors +while they browse, using your mobile device or instant messenger. Olark +is fully customizable, supports multiple operators and keeps chat +transcripts. + +.. _Olark: http://www.olark.com/ + + +Installation +============ + +To start using the Olark 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 Olark 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:`olark-configuration`. + +The Olark Javascript code is inserted into templates using a template +tag. Load the :mod:`olark` template tag library and insert the +:ttag:`olark` 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 olark %} + ... + {% olark %} + + + + +.. _olark-configuration: + +Configuration +============= + +Before you can use the Olark integration, you must first set your site +ID. You can also customize the visitor nickname and add information to +their status in the operator buddy list. + + +Setting the site ID +------------------- + +In order to install the chat code, you need to set your Olark site ID. +The :ttag:`olark` tag will include it in the rendered Javascript code. +You can find the site ID on `installation page`_ of you Olark account. +Set :const:`OLARK_SITE_ID` in the project :file:`settings.py` file:: + + OLARK_SITE_ID = 'XXXX-XXX-XX-XXXX' + +If you do not set the site ID, the chat window will not be rendered. + +.. _`installation page`: https://www.olark.com/install + + +Setting the visitor nickname +---------------------------- + +If your websites identifies visitors, you can use that to set their +nickname in the operator buddy list. By default, the name and username +of an authenticated user are automatically used to set the nickname. +See :ref:`identifying-visitors`. + +You can also set the visitor nickname yourself by adding either the +``olark_nickname`` (alias: ``olark_identity``) or the +``analytical_identity`` variable to the template context. If both +variables are set, the former takes precedence. For example:: + + context = RequestContext({'olark_nickname': nick}) + 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 set_olark_nickname(request): + try: + return {'olark_nickname': 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. + +See also `api.chat.updateVisitorNickname`_ in the Olark Javascript API +documentation. + +.. _`api.chat.updateVisitorNickname`: http://www.olark.com/documentation/javascript/api.chat.updateVisitorNickname + + +Adding status information +------------------------- + +If you want to send more information about the visitor to the operators, +you can add text snippets to the status field in the buddy list. Set +the ``olark_status`` context variable to a string or a list of strings +and the :ttag:`olark` tag will pass them to Olark as status messages:: + + context = RequestContext({'olark_status': [ + 'has %d items in cart' % cart.item_count, + 'value of items is $%0.2f' % cart.total_value, + ]}) + return some_template.render(context) + +See also `api.chat.updateVisitorStatus`_ in the Olark Javascript API +documentation. + +.. _`api.chat.updateVisitorStatus`: http://www.olark.com/documentation/javascript/api.chat.updateVisitorStatus + +---- + +Thanks go to Olark for their support with the development of this +application.