Merge branch '2551-feature-track-events'

This commit is contained in:
John Glover 2012-07-23 11:53:00 +01:00
commit 0cb3944ccd
4 changed files with 152 additions and 62 deletions

View File

@ -60,12 +60,10 @@ Installation
Finally, there are some optional configuration settings (shown here
with their default settings)::
googleanalytics.show_downloads = true
googleanalytics.resource_prefix = /downloads/
googleanalytics.domain = auto
If ``show_downloads`` is set, a download count for resources will
be displayed on individual package pages.
googleanalytics.show_downloads = true
googleanalytics.track_events = false
``resource_prefix`` is an arbitrary identifier so that we can query
for downloads in Google Analytics. It can theoretically be any
@ -76,8 +74,16 @@ Installation
``domain`` allows you to specify a domain against which Analytics
will track users. You will usually want to leave this as ``auto``;
if you are tracking users from multiple subdomains, you might want
to specify something like ``.mydomain.com``. See `Google's
documentation <http://code.google.com/apis/analytics/docs/gaJS/gaJSApiDomainDirectory.html#_gat.GA_Tracker_._setDomainName>`_ for more info.
to specify something like ``.mydomain.com``.
See `Google's documentation
<http://code.google.com/apis/analytics/docs/gaJS/gaJSApiDomainDirectory.html#_gat.GA_Tracker_._setDomainName>`_
for more info.
If ``show_downloads`` is set, a download count for resources will
be displayed on individual package pages.
If ``track_events`` is set, Google Analytics event tracking will be
enabled.
5. Restart CKAN (e.g. by restarting Apache)

View File

@ -1,4 +1,4 @@
gacode = """
header_code = """
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', '%s']);
@ -11,3 +11,15 @@ gacode = """
})();
</script>
"""
footer_code = """
<script type="text/javascript" src="%s"></script>
"""
download_style = """
<style type="text/css">
span.downloads-count {
font-size: 0.9em;
}
</style>
"""

View File

@ -1,17 +1,15 @@
import logging
import urllib
import os
from paste.deploy.converters import asbool
from genshi.filters import Transformer
from genshi import HTML
from genshi.core import START, TEXT
from genshi.filters.transform import INSIDE, EXIT
from pylons import config, request
from ckan.plugins import implements, SingletonPlugin
from ckan.plugins import IGenshiStreamFilter, IConfigurable, IRoutes
from ckan.plugins import IConfigurer
from gasnippet import gacode
from commands import DEFAULT_RESOURCE_URL_TAG
import pylons
import ckan.lib.helpers as h
import ckan.plugins as p
import gasnippet
import commands
import dbutil
log = logging.getLogger('ckanext.googleanalytics')
@ -21,44 +19,69 @@ class GoogleAnalyticsException(Exception):
pass
class GoogleAnalyticsPlugin(SingletonPlugin):
implements(IConfigurable, inherit=True)
implements(IGenshiStreamFilter, inherit=True)
implements(IRoutes, inherit=True)
implements(IConfigurer, inherit=True)
class GoogleAnalyticsPlugin(p.SingletonPlugin):
p.implements(p.IConfigurable, inherit=True)
p.implements(p.IGenshiStreamFilter, inherit=True)
p.implements(p.IRoutes, inherit=True)
p.implements(p.IConfigurer, inherit=True)
def configure(self, config):
self.config = config
if (not 'googleanalytics.id' in config):
msg = "Missing googleanalytics.id in config"
raise GoogleAnalyticsException(msg)
def filter(self, stream):
log.info("Inserting GA code into template")
ga_id = self.config['googleanalytics.id']
ga_domain = self.config.get('googleanalytics.domain', 'auto')
code = HTML(gacode % (ga_id, ga_domain))
stream = stream | Transformer('head').append(code)
resource_url = config.get('googleanalytics.resource_prefix',
DEFAULT_RESOURCE_URL_TAG)
ga_id = config['googleanalytics.id']
ga_domain = config.get('googleanalytics.domain', 'auto')
js_url = h.url_for_static('/scripts/ckanext-googleanalytics.js')
self.resource_url = config.get('googleanalytics.resource_prefix',
commands.DEFAULT_RESOURCE_URL_TAG)
self.show_downloads = asbool(
config.get('googleanalytics.show_downloads', True)
)
self.track_events = asbool(
config.get('googleanalytics.track_events', False)
)
routes = request.environ.get('pylons.routes_dict')
action = routes.get('action')
self.header_code = HTML(gasnippet.header_code % (ga_id, ga_domain))
self.footer_code = HTML(gasnippet.footer_code % js_url)
def update_config(self, config):
p.toolkit.add_template_directory(config, 'templates')
p.toolkit.add_public_directory(config, 'public')
def after_map(self, map):
map.redirect("/analytics/package/top", "/analytics/dataset/top")
map.connect(
'analytics', '/analytics/dataset/top',
controller='ckanext.googleanalytics.controller:GAController',
action='view'
)
return map
def filter(self, stream):
log.info("Inserting Google Analytics code into template")
stream = stream | Transformer('head').append(self.header_code)
if self.track_events:
stream = stream | Transformer('body/div[@id="scripts"]')\
.append(self.footer_code)
routes = pylons.request.environ.get('pylons.routes_dict')
action = routes.get('action')
controller = routes.get('controller')
if (controller == 'package' and \
action in ['search', 'read', 'resource_read']) or \
(controller == 'group' and action == 'read'):
log.info("Tracking of resource downloads")
show_downloads = (
asbool(config.get('googleanalytics.show_downloads', True)) and
action == 'read' and controller == 'package'
)
# add download tracking link
def js_attr(name, event):
attrs = event[1][1]
href = attrs.get('href').encode('utf-8')
link = '%s%s' % (resource_url, urllib.quote(href))
link = '%s%s' % (self.resource_url, urllib.quote(href))
js = "javascript: _gaq.push(['_trackPageview', '%s']);" % link
return js
@ -77,38 +100,15 @@ class GoogleAnalyticsPlugin(SingletonPlugin):
yield INSIDE, (TEXT, HTML(download_html % count), pos)
yield mark, (kind, data, pos)
# and some styling
download_style = '''
<style type="text/css">
span.downloads-count {
font-size: 0.9em;
}
</style>
'''
# perform the stream transform
stream = stream | Transformer('//a[contains(@class, "resource-url-analytics")]')\
.attr('onclick', js_attr)
if show_downloads:
if (self.show_downloads and action == 'read' and
controller == 'package'):
stream = stream | Transformer('//a[contains(@class, "resource-url-analytics")]')\
.apply(download_adder)
stream = stream | Transformer('//head').append(HTML(download_style))
stream = stream | Transformer('//head')\
.append(HTML(gasnippet.download_style))
return stream
def after_map(self, map):
map.redirect("/analytics/package/top", "/analytics/dataset/top")
map.connect('analytics', '/analytics/dataset/top',
controller='ckanext.googleanalytics.controller:GAController',
action='view')
return map
def update_config(self, config):
here = os.path.dirname(__file__)
rootdir = os.path.dirname(os.path.dirname(here))
template_dir = os.path.join(rootdir, 'ckanext',
'googleanalytics', 'templates')
config['extra_template_paths'] = ','.join(
[template_dir, config.get('extra_template_paths', '')]
)

View File

@ -0,0 +1,72 @@
(function ($) {
$(document).ready(function () {
// Google Analytics event tracking
// group links on home page
$('body.home div.group a').click(function() {
_gaq.push(['_trackEvent', 'Home', 'Click: Group Link', $(this).attr('href')]);
});
// clicking on user name (go to profile)
$('div.account span.ckan-logged-in a').first().click(function() {
_gaq.push(['_trackEvent', 'User', 'Click: User Name', $(this).attr('href')]);
});
// In user profile, clicking on Edit Profile
$('body.user div#minornavigation a')
.filter(function(index) {return $(this).text() === "Edit Profile";})
.click(function() {
_gaq.push(['_trackEvent', 'User', 'Click: Tab', 'Edit Profile']);
});
// Clicking Save Changes on Edit Profile page
$('body.user.edit input#save').click(function() {
_gaq.push(['_trackEvent', 'User', 'Click: Button', 'Save Profile Changes']);
});
// Clicking on any dataset link on User Profile page
$('body.user.read ul.datasets a').click(function() {
_gaq.push(['_trackEvent', 'User', 'Click: Dataset Link', $(this).attr('href')]);
});
// Compare Button on /dataset/history/X
$('body.package.history form#dataset-revisions input[name="diff"]').click(function() {
_gaq.push(['_trackEvent', 'Dataset', 'Click: Button', 'Compare History']);
});
// Tags on right hand sidebar of /dataset/X
$('body.package.read div#sidebar h3')
.filter(function(index) {return $(this).text().indexOf("Tags") != -1;})
.next('ul')
.find('a')
.click(function() {
_gaq.push(['_trackEvent', 'Dataset', 'Click: Tag', $(this).attr('href')]);
});
// Any of the group links on /group
$('body.group.index table.groups a').click(function() {
_gaq.push(['_trackEvent', 'Group', 'Click: Group Link', $(this).attr('href')]);
});
// Clicking any of the right hand sidebar tags on /group/X
$('body.group.read div#sidebar h2')
.filter(function(index) {return $(this).text().indexOf("Tags") != -1;})
.next('ul')
.find('a')
.click(function() {
_gaq.push(['_trackEvent', 'Group', 'Click: Tag', $(this).attr('href')]);
});
// Visiting /group/history/X
$('body.group div#minornavigation ul.nav a')
.filter(function(index) {return $(this).text().indexOf("History") != -1;})
.click(function() {
_gaq.push(['_trackEvent', 'Group', 'Click: History Tab', $(this).attr('href')]);
});
// Compare Button on /group/history/X
$('body.group.history form#group-revisions input[name="diff"]').click(function() {
_gaq.push(['_trackEvent', 'Group', 'Click: Button', 'Compare History']);
});
});
}(jQuery));