From: Maxious Date: Sat, 19 Oct 2013 11:40:42 +0000 Subject: Google Analytics for CKAN API X-Git-Url: https://maxious.lambdacomplex.org/git/?p=ckanext-datagovau.git&a=commitdiff&h=eed1a110e4836ff6fed5386d2ec19a781c92ff9d --- Google Analytics for CKAN API --- --- /dev/null +++ b/admin/reset.sh @@ -1,1 +1,17 @@ +paster --plugin=ckan db clean --config=development.ini +echo "drop extension postgis cascade;" | psql -d ckantest +paster --plugin=ckan db clean --config=development.ini +#to initiate for first time instead of load from dump +#paster --plugin=ckan db init --config=development.in +#paster --plugin=ckan user add maxious password=snmc email=maxious@gmail.com +#paster --plugin=ckan sysadmin add maxious +#paster --plugin=ckan db dump dump.db + +#paster --plugin=ckan db load --config=development.ini dump.db +paster --plugin=ckan db load --config=development.ini dump.harvest.db +echo "create extension postgis;" | psql -d ckantest +#sleep 2 +paster --plugin=ckan search-index rebuild --config=development.ini +#rm -r /tmp/pairtree_* + --- /dev/null +++ b/ckanext/datagovau/controller.py @@ -1,1 +1,82 @@ +import urllib +import json +from pprint import pprint +import logging +import ckan.logic as logic +import hashlib +import threading +from ckan.common import _, c, request, response +from pylons import config +log = logging.getLogger(__name__) + +from ckan.controllers.api import ApiController + +class DGAApiController(ApiController): + + def _post_analytics(self,user,request_obj_type,request_function,request_id): + if (config.get('googleanalytics.id') != None): + data = urllib.urlencode({ + "v":1, + "tid":config.get('googleanalytics.id'), + "cid":hashlib.md5(user).hexdigest(), + "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, + }) + log.debug("Sending API Analytics Data: "+data) + # send analytics asynchronously + threading.Thread(target=urllib.urlopen,args=("http://www.google-analytics.com/collect", data)).start() + + + def action(self, logic_function, ver=None): + try: + function = logic.get_action(logic_function) + except Exception,e: + log.debug(e) + pass + try: + 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.keys(): + id = request_data['q'] + if 'query' in request_data.keys(): + id = request_data['query'] + self._post_analytics(c.user,logic_function,'', id) + except Exception,e: + print 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: + print str(e) + pass + self._post_analytics(c.user,register,"search",id) + --- a/ckanext/datagovau/plugin.py +++ b/ckanext/datagovau/plugin.py @@ -6,6 +6,7 @@ import ckan.plugins.toolkit as tk import ckan.model as model from pylons import config +from routes.mapper import SubMapper, Mapper as _Mapper from sqlalchemy import orm import ckan.model @@ -29,17 +30,6 @@ lib.helpers.get_action('user_activity_list',{'id':user_dict['id']}) if x['data'].get('package')] return created_datasets_list + active_datasets_list -def get_dga_stats(): - connection = model.Session.connection() - res = connection.execute("SELECT 'organization', count(*) from \"group\" where type = 'organization' and state = 'active' union select 'package', count(*) from package where state='active' or state='draft' or state='draft-complete' union select 'resource', count(*) from resource where state='active' union select name||role, 0 from user_object_role inner join \"user\" on user_object_role.user_id = \"user\".id where name not in ('logged_in','visitor') group by name,role;") - return res - - -def get_activity_counts(): - connection = model.Session.connection() - res = connection.execute("select to_char(timestamp, 'YYYY-MM') as month,activity_type, count(*) from activity group by month, activity_type order by month;").fetchall(); - return res - class DataGovAuPlugin(plugins.SingletonPlugin, tk.DefaultDatasetForm): @@ -51,6 +41,55 @@ plugins.implements(plugins.IConfigurer, inherit=False) plugins.implements(plugins.IDatasetForm, inherit=False) plugins.implements(plugins.ITemplateHelpers, inherit=False) + plugins.implements(plugins.IRoutes, inherit=True) + + def before_map(self, map): + + # 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.datagovau.controller:DGAApiController', 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.datagovau.controller:DGAApiController', 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.datagovau.controller:DGAApiController', 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 update_config(self, config): # Add this plugin's templates dir to CKAN's extra_template_paths, so @@ -64,7 +103,7 @@ # config['licenses_group_url'] = 'http://%(ckan.site_url)/licenses.json' def get_helpers(self): - return {'get_last_active_user': get_last_active_user, 'get_user_datasets': get_user_datasets, 'get_dga_stats': get_dga_stats, 'get_activity_counts': get_activity_counts} + return {'get_last_active_user': get_last_active_user, 'get_user_datasets': get_user_datasets} def is_fallback(self): # Return True to register this plugin as the default handler for