Revert "Merge pull request #6 from datagovau/api-analytics-event-tracking"
This reverts commit0febe11dc5
, reversing changes made toe45d73d7a3
. This has been reverted for caushing Apache to max out threads when running under mod_wsgi.
This commit is contained in:
parent
0febe11dc5
commit
f4fce47601
|
@ -18,9 +18,6 @@ Features
|
||||||
resource downloads will be displayed as Events in the Google Analytics
|
resource downloads will be displayed as Events in the Google Analytics
|
||||||
reporting interface.
|
reporting interface.
|
||||||
|
|
||||||
* Adds Google Analytics Event Tracking to some API calls so that usage of the
|
|
||||||
API can be reported on via Google Analytics.
|
|
||||||
|
|
||||||
* Adds Google Analytics Event Tracking to group links on the home page,
|
* Adds Google Analytics Event Tracking to group links on the home page,
|
||||||
user profile links, editing and saving user profiles, etc.
|
user profile links, editing and saving user profiles, etc.
|
||||||
|
|
||||||
|
|
|
@ -1,151 +1,12 @@
|
||||||
import logging
|
import logging
|
||||||
from ckan.lib.base import BaseController, c, render, request
|
from ckan.lib.base import BaseController, c, render
|
||||||
import dbutil
|
import dbutil
|
||||||
|
|
||||||
import urllib
|
|
||||||
import urllib2
|
|
||||||
|
|
||||||
import logging
|
|
||||||
import ckan.logic as logic
|
|
||||||
import hashlib
|
|
||||||
import Queue
|
|
||||||
import threading
|
|
||||||
from pylons import config
|
|
||||||
|
|
||||||
from webob.multidict import UnicodeMultiDict
|
|
||||||
from paste.util.multidict import MultiDict
|
|
||||||
|
|
||||||
from ckan.controllers.api import ApiController
|
|
||||||
|
|
||||||
log = logging.getLogger('ckanext.googleanalytics')
|
log = logging.getLogger('ckanext.googleanalytics')
|
||||||
|
|
||||||
|
|
||||||
class GAController(BaseController):
|
class GAController(BaseController):
|
||||||
def view(self):
|
def view(self):
|
||||||
# get package objects corresponding to popular GA content
|
# get package objects corresponding to popular GA content
|
||||||
c.top_packages = dbutil.get_top_packages(limit=10)
|
c.top_packages = dbutil.get_top_packages(limit=10)
|
||||||
c.top_resources = dbutil.get_top_resources(limit=10)
|
c.top_resources = dbutil.get_top_resources(limit=10)
|
||||||
return render('summary.html')
|
return render('summary.html')
|
||||||
|
|
||||||
|
|
||||||
class AnalyticsPostThread(threading.Thread):
|
|
||||||
"""Threaded Url POST"""
|
|
||||||
def __init__(self, queue):
|
|
||||||
threading.Thread.__init__(self)
|
|
||||||
self.queue = queue
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
while True:
|
|
||||||
# grabs host from queue
|
|
||||||
data_dict = self.queue.get()
|
|
||||||
|
|
||||||
data = urllib.urlencode(data_dict)
|
|
||||||
log.debug("Sending API event to Google Analytics: " + data)
|
|
||||||
# send analytics
|
|
||||||
urllib2.urlopen(
|
|
||||||
"http://www.google-analytics.com/collect",
|
|
||||||
data,
|
|
||||||
# timeout in seconds
|
|
||||||
# https://docs.python.org/2/library/urllib2.html#urllib2.urlopen
|
|
||||||
10)
|
|
||||||
|
|
||||||
# signals to queue job is done
|
|
||||||
self.queue.task_done()
|
|
||||||
|
|
||||||
|
|
||||||
class GAApiController(ApiController):
|
|
||||||
# intercept API calls to record via google analytics
|
|
||||||
analytics_queue = Queue.Queue()
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
# spawn a pool of 5 threads, and pass them queue instance
|
|
||||||
for i in range(5):
|
|
||||||
t = AnalyticsPostThread(self.analytics_queue)
|
|
||||||
t.setDaemon(True)
|
|
||||||
t.start()
|
|
||||||
|
|
||||||
def _post_analytics(
|
|
||||||
self, user, request_obj_type, request_function, request_id):
|
|
||||||
if config.get('googleanalytics.id'):
|
|
||||||
data_dict = {
|
|
||||||
"v": 1,
|
|
||||||
"tid": config.get('googleanalytics.id'),
|
|
||||||
"cid": hashlib.md5(user).hexdigest(),
|
|
||||||
# customer id should be obfuscated
|
|
||||||
"t": "event",
|
|
||||||
"dh": c.environ['HTTP_HOST'],
|
|
||||||
"dp": c.environ['PATH_INFO'],
|
|
||||||
"dr": c.environ.get('HTTP_REFERER', ''),
|
|
||||||
"ec": "CKAN API Request",
|
|
||||||
"ea": request_obj_type+request_function,
|
|
||||||
"el": request_id,
|
|
||||||
}
|
|
||||||
self.analytics_queue.put(data_dict)
|
|
||||||
|
|
||||||
def action(self, logic_function, ver=None):
|
|
||||||
try:
|
|
||||||
function = logic.get_action(logic_function)
|
|
||||||
side_effect_free = getattr(function, 'side_effect_free', False)
|
|
||||||
request_data = self._get_request_data(
|
|
||||||
try_url_params=side_effect_free)
|
|
||||||
if isinstance(request_data, dict):
|
|
||||||
id = request_data.get('id', '')
|
|
||||||
if 'q' in request_data:
|
|
||||||
id = request_data['q']
|
|
||||||
if 'query' in request_data:
|
|
||||||
id = request_data['query']
|
|
||||||
self._post_analytics(c.user, logic_function, '', id)
|
|
||||||
except Exception, e:
|
|
||||||
log.debug(e)
|
|
||||||
pass
|
|
||||||
|
|
||||||
return ApiController.action(self, logic_function, ver)
|
|
||||||
|
|
||||||
def list(self, ver=None, register=None,
|
|
||||||
subregister=None, id=None):
|
|
||||||
self._post_analytics(c.user,
|
|
||||||
register +
|
|
||||||
("_"+str(subregister) if subregister else ""),
|
|
||||||
"list",
|
|
||||||
id)
|
|
||||||
return ApiController.list(self, ver, register, subregister, id)
|
|
||||||
|
|
||||||
def show(self, ver=None, register=None,
|
|
||||||
subregister=None, id=None, id2=None):
|
|
||||||
self._post_analytics(c.user,
|
|
||||||
register +
|
|
||||||
("_"+str(subregister) if subregister else ""),
|
|
||||||
"show",
|
|
||||||
id)
|
|
||||||
return ApiController.show(self, ver, register, subregister, id, id2)
|
|
||||||
|
|
||||||
def update(self, ver=None, register=None,
|
|
||||||
subregister=None, id=None, id2=None):
|
|
||||||
self._post_analytics(c.user,
|
|
||||||
register +
|
|
||||||
("_"+str(subregister) if subregister else ""),
|
|
||||||
"update",
|
|
||||||
id)
|
|
||||||
return ApiController.update(self, ver, register, subregister, id, id2)
|
|
||||||
|
|
||||||
def delete(self, ver=None, register=None,
|
|
||||||
subregister=None, id=None, id2=None):
|
|
||||||
self._post_analytics(c.user,
|
|
||||||
register +
|
|
||||||
("_"+str(subregister) if subregister else ""),
|
|
||||||
"delete",
|
|
||||||
id)
|
|
||||||
return ApiController.delete(self, ver, register, subregister, id, id2)
|
|
||||||
|
|
||||||
def search(self, ver=None, register=None):
|
|
||||||
id = None
|
|
||||||
try:
|
|
||||||
params = MultiDict(self._get_search_params(request.params))
|
|
||||||
if 'q' in params.keys():
|
|
||||||
id = params['q']
|
|
||||||
if 'query' in params.keys():
|
|
||||||
id = params['query']
|
|
||||||
except ValueError, e:
|
|
||||||
log.debug(str(e))
|
|
||||||
pass
|
|
||||||
self._post_analytics(c.user, register, "search", id)
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ this.ckan.module('google-analytics', function(jQuery, _) {
|
||||||
jQuery('a.resource-url-analytics').on('click', function() {
|
jQuery('a.resource-url-analytics').on('click', function() {
|
||||||
var resource_url = encodeURIComponent(jQuery(this).prop('href'));
|
var resource_url = encodeURIComponent(jQuery(this).prop('href'));
|
||||||
if (resource_url) {
|
if (resource_url) {
|
||||||
ga('send', 'event', 'Resource', 'Download', resource_url);
|
_gaq.push(['_trackEvent', 'Resource', 'Download', resource_url]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@ import pylons
|
||||||
import ckan.lib.helpers as h
|
import ckan.lib.helpers as h
|
||||||
import ckan.plugins as p
|
import ckan.plugins as p
|
||||||
import gasnippet
|
import gasnippet
|
||||||
from routes.mapper import SubMapper, Mapper as _Mapper
|
|
||||||
|
|
||||||
log = logging.getLogger('ckanext.googleanalytics')
|
log = logging.getLogger('ckanext.googleanalytics')
|
||||||
|
|
||||||
|
@ -68,58 +67,6 @@ class GoogleAnalyticsPlugin(p.SingletonPlugin):
|
||||||
else:
|
else:
|
||||||
p.toolkit.add_template_directory(config, 'templates')
|
p.toolkit.add_template_directory(config, 'templates')
|
||||||
|
|
||||||
def before_map(self, map):
|
|
||||||
'''Add new routes that this extension's controllers handle.
|
|
||||||
|
|
||||||
See IRoutes.
|
|
||||||
|
|
||||||
'''
|
|
||||||
# Helpers to reduce code clutter
|
|
||||||
GET = dict(method=['GET'])
|
|
||||||
PUT = dict(method=['PUT'])
|
|
||||||
POST = dict(method=['POST'])
|
|
||||||
DELETE = dict(method=['DELETE'])
|
|
||||||
GET_POST = dict(method=['GET', 'POST'])
|
|
||||||
# intercept API calls that we want to capture analytics on
|
|
||||||
register_list = [
|
|
||||||
'package',
|
|
||||||
'dataset',
|
|
||||||
'resource',
|
|
||||||
'tag',
|
|
||||||
'group',
|
|
||||||
'related',
|
|
||||||
'revision',
|
|
||||||
'licenses',
|
|
||||||
'rating',
|
|
||||||
'user',
|
|
||||||
'activity'
|
|
||||||
]
|
|
||||||
register_list_str = '|'.join(register_list)
|
|
||||||
# /api ver 3 or none
|
|
||||||
with SubMapper(map, controller='ckanext.googleanalytics.controller:GAApiController', path_prefix='/api{ver:/3|}',
|
|
||||||
ver='/3') as m:
|
|
||||||
m.connect('/action/{logic_function}', action='action',
|
|
||||||
conditions=GET_POST)
|
|
||||||
|
|
||||||
# /api ver 1, 2, 3 or none
|
|
||||||
with SubMapper(map, controller='ckanext.googleanalytics.controller:GAApiController', path_prefix='/api{ver:/1|/2|/3|}',
|
|
||||||
ver='/1') as m:
|
|
||||||
m.connect('/search/{register}', action='search')
|
|
||||||
|
|
||||||
# /api/rest ver 1, 2 or none
|
|
||||||
with SubMapper(map, controller='ckanext.googleanalytics.controller:GAApiController', path_prefix='/api{ver:/1|/2|}',
|
|
||||||
ver='/1', requirements=dict(register=register_list_str)
|
|
||||||
) as m:
|
|
||||||
|
|
||||||
m.connect('/rest/{register}', action='list', conditions=GET)
|
|
||||||
m.connect('/rest/{register}', action='create', conditions=POST)
|
|
||||||
m.connect('/rest/{register}/{id}', action='show', conditions=GET)
|
|
||||||
m.connect('/rest/{register}/{id}', action='update', conditions=PUT)
|
|
||||||
m.connect('/rest/{register}/{id}', action='update', conditions=POST)
|
|
||||||
m.connect('/rest/{register}/{id}', action='delete', conditions=DELETE)
|
|
||||||
|
|
||||||
return map
|
|
||||||
|
|
||||||
def after_map(self, map):
|
def after_map(self, map):
|
||||||
'''Add new routes that this extension's controllers handle.
|
'''Add new routes that this extension's controllers handle.
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
var _gaq = _gaq || [];
|
||||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
_gaq.push(['_setAccount', '{{googleanalytics_id}}']);
|
||||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
_gaq.push(['_setDomainName', '{{googleanalytics_domain}}']);
|
||||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
_gaq.push(['_trackPageview']);
|
||||||
|
(function() {
|
||||||
ga('create', '{{googleanalytics_id}}', '{{googleanalytics_domain}}');
|
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||||
ga('set', 'anonymizeIp', true);
|
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||||
ga('send', 'pageview');
|
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||||
|
})();
|
||||||
</script>
|
</script>
|
||||||
|
|
Loading…
Reference in New Issue