Merge branch '2551-feature-track-events'
This commit is contained in:
commit
0cb3944ccd
18
README.rst
18
README.rst
|
@ -60,12 +60,10 @@ Installation
|
||||||
Finally, there are some optional configuration settings (shown here
|
Finally, there are some optional configuration settings (shown here
|
||||||
with their default settings)::
|
with their default settings)::
|
||||||
|
|
||||||
googleanalytics.show_downloads = true
|
|
||||||
googleanalytics.resource_prefix = /downloads/
|
googleanalytics.resource_prefix = /downloads/
|
||||||
googleanalytics.domain = auto
|
googleanalytics.domain = auto
|
||||||
|
googleanalytics.show_downloads = true
|
||||||
If ``show_downloads`` is set, a download count for resources will
|
googleanalytics.track_events = false
|
||||||
be displayed on individual package pages.
|
|
||||||
|
|
||||||
``resource_prefix`` is an arbitrary identifier so that we can query
|
``resource_prefix`` is an arbitrary identifier so that we can query
|
||||||
for downloads in Google Analytics. It can theoretically be any
|
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
|
``domain`` allows you to specify a domain against which Analytics
|
||||||
will track users. You will usually want to leave this as ``auto``;
|
will track users. You will usually want to leave this as ``auto``;
|
||||||
if you are tracking users from multiple subdomains, you might want
|
if you are tracking users from multiple subdomains, you might want
|
||||||
to specify something like ``.mydomain.com``. See `Google's
|
to specify something like ``.mydomain.com``.
|
||||||
documentation <http://code.google.com/apis/analytics/docs/gaJS/gaJSApiDomainDirectory.html#_gat.GA_Tracker_._setDomainName>`_ for more info.
|
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)
|
5. Restart CKAN (e.g. by restarting Apache)
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
gacode = """
|
header_code = """
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
var _gaq = _gaq || [];
|
var _gaq = _gaq || [];
|
||||||
_gaq.push(['_setAccount', '%s']);
|
_gaq.push(['_setAccount', '%s']);
|
||||||
|
@ -11,3 +11,15 @@ gacode = """
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
footer_code = """
|
||||||
|
<script type="text/javascript" src="%s"></script>
|
||||||
|
"""
|
||||||
|
|
||||||
|
download_style = """
|
||||||
|
<style type="text/css">
|
||||||
|
span.downloads-count {
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
"""
|
||||||
|
|
|
@ -1,17 +1,15 @@
|
||||||
import logging
|
import logging
|
||||||
import urllib
|
import urllib
|
||||||
import os
|
|
||||||
from paste.deploy.converters import asbool
|
from paste.deploy.converters import asbool
|
||||||
from genshi.filters import Transformer
|
from genshi.filters import Transformer
|
||||||
from genshi import HTML
|
from genshi import HTML
|
||||||
from genshi.core import START, TEXT
|
from genshi.core import START, TEXT
|
||||||
from genshi.filters.transform import INSIDE, EXIT
|
from genshi.filters.transform import INSIDE, EXIT
|
||||||
from pylons import config, request
|
import pylons
|
||||||
from ckan.plugins import implements, SingletonPlugin
|
import ckan.lib.helpers as h
|
||||||
from ckan.plugins import IGenshiStreamFilter, IConfigurable, IRoutes
|
import ckan.plugins as p
|
||||||
from ckan.plugins import IConfigurer
|
import gasnippet
|
||||||
from gasnippet import gacode
|
import commands
|
||||||
from commands import DEFAULT_RESOURCE_URL_TAG
|
|
||||||
import dbutil
|
import dbutil
|
||||||
|
|
||||||
log = logging.getLogger('ckanext.googleanalytics')
|
log = logging.getLogger('ckanext.googleanalytics')
|
||||||
|
@ -21,44 +19,69 @@ class GoogleAnalyticsException(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class GoogleAnalyticsPlugin(SingletonPlugin):
|
class GoogleAnalyticsPlugin(p.SingletonPlugin):
|
||||||
implements(IConfigurable, inherit=True)
|
p.implements(p.IConfigurable, inherit=True)
|
||||||
implements(IGenshiStreamFilter, inherit=True)
|
p.implements(p.IGenshiStreamFilter, inherit=True)
|
||||||
implements(IRoutes, inherit=True)
|
p.implements(p.IRoutes, inherit=True)
|
||||||
implements(IConfigurer, inherit=True)
|
p.implements(p.IConfigurer, inherit=True)
|
||||||
|
|
||||||
def configure(self, config):
|
def configure(self, config):
|
||||||
self.config = config
|
|
||||||
if (not 'googleanalytics.id' in config):
|
if (not 'googleanalytics.id' in config):
|
||||||
msg = "Missing googleanalytics.id in config"
|
msg = "Missing googleanalytics.id in config"
|
||||||
raise GoogleAnalyticsException(msg)
|
raise GoogleAnalyticsException(msg)
|
||||||
|
|
||||||
def filter(self, stream):
|
ga_id = config['googleanalytics.id']
|
||||||
log.info("Inserting GA code into template")
|
ga_domain = config.get('googleanalytics.domain', 'auto')
|
||||||
ga_id = self.config['googleanalytics.id']
|
js_url = h.url_for_static('/scripts/ckanext-googleanalytics.js')
|
||||||
ga_domain = self.config.get('googleanalytics.domain', 'auto')
|
self.resource_url = config.get('googleanalytics.resource_prefix',
|
||||||
code = HTML(gacode % (ga_id, ga_domain))
|
commands.DEFAULT_RESOURCE_URL_TAG)
|
||||||
stream = stream | Transformer('head').append(code)
|
self.show_downloads = asbool(
|
||||||
resource_url = config.get('googleanalytics.resource_prefix',
|
config.get('googleanalytics.show_downloads', True)
|
||||||
DEFAULT_RESOURCE_URL_TAG)
|
)
|
||||||
|
self.track_events = asbool(
|
||||||
|
config.get('googleanalytics.track_events', False)
|
||||||
|
)
|
||||||
|
|
||||||
routes = request.environ.get('pylons.routes_dict')
|
self.header_code = HTML(gasnippet.header_code % (ga_id, ga_domain))
|
||||||
action = routes.get('action')
|
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')
|
controller = routes.get('controller')
|
||||||
|
|
||||||
if (controller == 'package' and \
|
if (controller == 'package' and \
|
||||||
action in ['search', 'read', 'resource_read']) or \
|
action in ['search', 'read', 'resource_read']) or \
|
||||||
(controller == 'group' and action == 'read'):
|
(controller == 'group' and action == 'read'):
|
||||||
|
|
||||||
log.info("Tracking of resource downloads")
|
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
|
# add download tracking link
|
||||||
def js_attr(name, event):
|
def js_attr(name, event):
|
||||||
attrs = event[1][1]
|
attrs = event[1][1]
|
||||||
href = attrs.get('href').encode('utf-8')
|
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
|
js = "javascript: _gaq.push(['_trackPageview', '%s']);" % link
|
||||||
return js
|
return js
|
||||||
|
|
||||||
|
@ -77,38 +100,15 @@ class GoogleAnalyticsPlugin(SingletonPlugin):
|
||||||
yield INSIDE, (TEXT, HTML(download_html % count), pos)
|
yield INSIDE, (TEXT, HTML(download_html % count), pos)
|
||||||
yield mark, (kind, data, 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
|
# perform the stream transform
|
||||||
stream = stream | Transformer('//a[contains(@class, "resource-url-analytics")]')\
|
stream = stream | Transformer('//a[contains(@class, "resource-url-analytics")]')\
|
||||||
.attr('onclick', js_attr)
|
.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")]')\
|
stream = stream | Transformer('//a[contains(@class, "resource-url-analytics")]')\
|
||||||
.apply(download_adder)
|
.apply(download_adder)
|
||||||
stream = stream | Transformer('//head').append(HTML(download_style))
|
stream = stream | Transformer('//head')\
|
||||||
|
.append(HTML(gasnippet.download_style))
|
||||||
|
|
||||||
return stream
|
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', '')]
|
|
||||||
)
|
|
||||||
|
|
|
@ -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));
|
Loading…
Reference in New Issue