Adding site analytics at /data/analytics
Adding site analytics at /data/analytics

- Allows for download as CSV
- Also refactored the publisher urls to allow index page and a read for a specific publisher

import logging import logging
import operator import operator
from ckan.lib.base import BaseController, c, render,request from ckan.lib.base import BaseController, c, render, request, response
   
  import sqlalchemy
  from sqlalchemy import func, cast, Integer
import ckan.model as model import ckan.model as model
from ga_model import GA_Url from ga_model import GA_Url, GA_Stat
   
log = logging.getLogger('ckanext.ga-report') log = logging.getLogger('ckanext.ga-report')
   
   
  def _get_month_name(str):
  import calendar
  from time import strptime
  d = strptime('2012-10', '%Y-%m')
  return '%s %s' % (calendar.month_name[d.tm_mon], d.tm_year)
   
   
  def _month_details(cls):
  months = []
  vals = model.Session.query(cls.period_name).distinct().all()
  for m in vals:
  months.append( (m[0], _get_month_name(m)))
  return sorted(months, key=operator.itemgetter(0), reverse=True)
   
   
class GaReport(BaseController): class GaReport(BaseController):
   
  def csv(self, month):
  import csv
   
  entries = model.Session.query(GA_Stat).\
  filter(GA_Stat.period_name==month).\
  order_by('GA_Stat.stat_name, GA_Stat.key').all()
   
  response.headers['Content-disposition'] = 'attachment; filename=dgu_analytics_%s.csv' % (month)
  response.headers['Content-Type'] = "text/csv; charset=utf-8"
   
  writer = csv.writer(response)
  writer.writerow(["Period", "Statistic", "Key", "Value"])
   
  for entry in entries:
  writer.writerow([entry.period_name.encode('utf-8'),
  entry.stat_name.encode('utf-8'),
  entry.key.encode('utf-8'),
  entry.value.encode('utf-8')])
   
def index(self): def index(self):
   
  # Get the month details by fetching distinct values and determining the
  # month names from the values.
  c.months = _month_details(GA_Stat)
   
  # Work out which month to show, based on query params of the first item
  c.month = request.params.get('month', c.months[0][0] if c.months else '')
  c.month_desc = ''.join([m[1] for m in c.months if m[0]==c.month])
   
  entries = model.Session.query(GA_Stat).\
  filter(GA_Stat.stat_name=='Totals').\
  filter(GA_Stat.period_name==c.month).all()
  c.global_totals = [(s.key, s.value) for s in entries ]
   
  keys = {
  'Browser versions': 'browsers',
  'Operating Systems versions': 'os',
  'Social sources': 'social_networks',
  'Languages': 'languages',
  'Country': 'country'
  }
   
  for k, v in keys.iteritems():
  entries = model.Session.query(GA_Stat).\
  filter(GA_Stat.stat_name==k).\
  filter(GA_Stat.period_name==c.month).\
  order_by('ga_stat.value::int desc').all()
  setattr(c, v, [(s.key, s.value) for s in entries ])
   
   
return render('ga_report/site/index.html') return render('ga_report/site/index.html')
   
   
class GaPublisherReport(BaseController): class GaPublisherReport(BaseController):
""" """
Displays the pageview and visit count for specific publishers based on Displays the pageview and visit count for specific publishers based on
the datasets associated with the publisher. the datasets associated with the publisher.
""" """
   
def _get_month_name(self, str): def index(self):
import calendar # Get the month details by fetching distinct values and determining the
from time import strptime # month names from the values.
d = strptime('2012-10', '%Y-%m') c.months = _month_details(GA_Url)
return '%s %s' % (calendar.month_name[d.tm_mon], d.tm_year)  
  # Work out which month to show, based on query params of the first item
  c.month = request.params.get('month', c.months[0][0] if c.months else '')
  c.month_desc = ''.join([m[1] for m in c.months if m[0]==c.month])
   
  connection = model.Session.connection()
  q = """
  select department_id, sum(pageviews::int) views, sum(visitors::int) visits
  from ga_url
  where department_id <> ''
  and not url like '/publisher/%%'
  and period_name=%s
  group by department_id order by views desc limit 20;
  """
  c.top_publishers = []
  res = connection.execute(q, c.month)
  for row in res:
  c.top_publishers.append((model.Group.get(row[0]), row[1], row[2]))
   
  return render('ga_report/publisher/index.html')
   
   
def index(self, id): def read(self, id):
c.publisher = model.Group.get(id) c.publisher = model.Group.get(id)
c.top_packages = [] # package, dataset_views in c.top_packages c.top_packages = [] # package, dataset_views in c.top_packages
   
# Get the month details by fetching distinct values and determining the # Get the month details by fetching distinct values and determining the
# month names from the values. # month names from the values.
c.months = [] c.months = _month_details(GA_Url)
vals = model.Session.query(GA_Url.period_name).distinct().all()  
for m in vals:  
c.months.append( (m[0],self._get_month_name(m)))  
   
# Sort the months, so most recent is at the head of our list  
c.months = sorted(c.months, key=operator.itemgetter(0), reverse=True)  
   
# Work out which month to show, based on query params of the first item # Work out which month to show, based on query params of the first item
c.month = request.params.get('month', c.months[0][0] if c.months else '') c.month = request.params.get('month', c.months[0][0] if c.months else '')
c.month_desc = ''.join([m[1] for m in c.months if m[0]==c.month]) c.month_desc = ''.join([m[1] for m in c.months if m[0]==c.month])
   
entry = model.Session.query(GA_Url).\ entry = model.Session.query(GA_Url).\
filter(GA_Url.url=='/publisher/%s' % c.publisher.name).\ filter(GA_Url.url=='/publisher/%s' % c.publisher.name).\
filter(GA_Url.period_name==c.month).first() filter(GA_Url.period_name==c.month).first()
c.publisher_page_views = entry.pageviews if entry else 0 c.publisher_page_views = entry.pageviews if entry else 0
   
entries = model.Session.query(GA_Url).\ entries = model.Session.query(GA_Url).\
filter(GA_Url.department_id==c.publisher.name).\ filter(GA_Url.department_id==c.publisher.name).\
filter(GA_Url.period_name==c.month).\ filter(GA_Url.period_name==c.month).\
order_by('ga_url.pageviews desc')[:10] order_by('ga_url.pageviews::int desc')[:20]
for entry in entries: for entry in entries:
if entry.url.startswith('/dataset/'): if entry.url.startswith('/dataset/'):
p = model.Package.get(entry.url[len('/dataset/'):]) p = model.Package.get(entry.url[len('/dataset/'):])
c.top_packages.append((p,entry.pageviews,entry.visitors)) c.top_packages.append((p,entry.pageviews,entry.visitors))
   
return render('ga_report/publisher/index.html') return render('ga_report/publisher/read.html')
   
import logging import logging
import ckan.lib.helpers as h import ckan.lib.helpers as h
import ckan.plugins as p import ckan.plugins as p
from ckan.plugins import implements, toolkit from ckan.plugins import implements, toolkit
#import gasnippet #import gasnippet
#import commands #import commands
#import dbutil #import dbutil
   
log = logging.getLogger('ckanext.ga-report') log = logging.getLogger('ckanext.ga-report')
   
class GAReportPlugin(p.SingletonPlugin): class GAReportPlugin(p.SingletonPlugin):
implements(p.IConfigurer, inherit=True) implements(p.IConfigurer, inherit=True)
implements(p.IRoutes, inherit=True) implements(p.IRoutes, inherit=True)
   
def update_config(self, config): def update_config(self, config):
toolkit.add_template_directory(config, 'templates') toolkit.add_template_directory(config, 'templates')
toolkit.add_public_directory(config, 'public') toolkit.add_public_directory(config, 'public')
   
def after_map(self, map): def after_map(self, map):
map.connect( map.connect(
'/data/analytics/', '/data/analytics',
controller='ckanext.ga_report.controller:GaReport', controller='ckanext.ga_report.controller:GaReport',
  action='index'
  )
  map.connect(
  '/data/analytics_{month}.csv',
  controller='ckanext.ga_report.controller:GaReport',
  action='csv'
  )
  map.connect(
  '/data/analytics/publisher/',
  controller='ckanext.ga_report.controller:GaPublisherReport',
action='index' action='index'
) )
map.connect( map.connect(
'/data/analytics/publisher/{id}', '/data/analytics/publisher/{id}',
controller='ckanext.ga_report.controller:GaPublisherReport', controller='ckanext.ga_report.controller:GaPublisherReport',
action='index' action='read'
) )
return map return map
   
   
<html xmlns:py="http://genshi.edgewall.org/" <html xmlns:py="http://genshi.edgewall.org/"
xmlns:i18n="http://genshi.edgewall.org/i18n" xmlns:i18n="http://genshi.edgewall.org/i18n"
xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:xi="http://www.w3.org/2001/XInclude"
py:strip=""> py:strip="">
   
<py:def function="page_title">Analytics for ${g.site_title}</py:def> <py:def function="page_title">Publisher Analytics for ${g.site_title}</py:def>
   
<div py:match="content"> <div py:match="content">
<h1>Analytics for ${c.publisher.title}</h1> <h1>Publisher Analytics</h1>
  <h2>The top 20 publishers</h2>
   
<h2>Most viewed datasets</h2> <form class="form-inline" action="${h.url_for(controller='ckanext.ga_report.controller:GaPublisherReport',action='index')}" method="get">
<p><em>Note: this data does not include API calls</em></p>  
   
<form class="form-inline" action="${h.url_for(controller='ckanext.ga_report.controller:GaPublisherReport',action='index',id=c.publisher.name)}" method="get">  
<div class="controls"> <div class="controls">
<select name="month"> <select name="month">
<py:for each="val,desc in c.months"> <py:for each="val,desc in c.months">
<option value='${val}' py:attrs="{'selected': 'selected' if c.month == val else None}">${desc}</option> <option value='${val}' py:attrs="{'selected': 'selected' if c.month == val else None}">${desc}</option>
</py:for> </py:for>
</select> </select>
<input class="btn button" type='submit' value="Update"/> <input class="btn button" type='submit' value="Update"/>
</div> </div>
</form> </form>
   
<p><a href="${h.url_for(controller='ckanext.dgu.controllers.publisher:PublisherController', action='read', id=c.publisher.name)}">${c.publisher.title} dataset list</a> was viewed ${c.publisher_page_views} times in ${c.month_desc}</p>  
   
<table class="table table-condensed table-bordered table-striped"> <table class="table table-condensed table-bordered table-striped">
<tr> <tr>
<th>Dataset</th> <th>Publisher</th>
<th>Views</th> <th>Dataset Views</th>
<th>Visits</th> <th>Visits</th>
</tr> </tr>
<py:for each="package, views, visits in c.top_packages"> <py:for each="publisher, views, visits in c.top_publishers">
<tr> <tr>
<td>${h.link_to(package.title or package.name, h.url_for(controller='package', action='read', id=package.name))} <td>${h.link_to(publisher.title, h.url_for(controller='ckanext.ga_report.controller:GaPublisherReport', action='read', id=publisher.name))}
</td> </td>
<td>${views}</td> <td>${views}</td>
<td>${visits}</td> <td>${visits}</td>
</tr> </tr>
</py:for> </py:for>
</table> </table>
   
   
</div> </div>
   
<xi:include href="../../layout.html" /> <xi:include href="../../layout.html" />
   
  <py:def function="optional_footer">
  <script type='text/javascript'>
  $('.nav-tabs li a').click(function (e) {
  e.preventDefault();
  $(this).tab('show');
  })
  </script>
  </py:def>
   
</html> </html>
   
   
   
   
  <html xmlns:py="http://genshi.edgewall.org/"
  xmlns:i18n="http://genshi.edgewall.org/i18n"
  xmlns:xi="http://www.w3.org/2001/XInclude"
  py:strip="">
 
  <py:def function="page_title">Analytics for ${g.site_title}</py:def>
 
  <div py:match="content">
  <h1>Analytics for ${c.publisher.title}</h1>
 
  <h2>Top 20 most viewed datasets</h2>
  <p><em>Note: this data does not include API calls</em></p>
 
  <form class="form-inline" action="${h.url_for(controller='ckanext.ga_report.controller:GaPublisherReport',action='read',id=c.publisher.name)}" method="get">
  <div class="controls">
  <select name="month">
  <py:for each="val,desc in c.months">
  <option value='${val}' py:attrs="{'selected': 'selected' if c.month == val else None}">${desc}</option>
  </py:for>
  </select>
  <input class="btn button" type='submit' value="Update"/>
  </div>
  </form>
 
  <p><a href="${h.url_for(controller='ckanext.dgu.controllers.publisher:PublisherController', action='read', id=c.publisher.name)}">${c.publisher.title} dataset list</a> was viewed ${c.publisher_page_views} times in ${c.month_desc}</p>
 
  <table class="table table-condensed table-bordered table-striped">
  <tr>
  <th>Dataset</th>
  <th>Views</th>
  <th>Visits</th>
  </tr>
  <py:for each="package, views, visits in c.top_packages">
  <tr>
  <td>${h.link_to(package.title or package.name, h.url_for(controller='package', action='read', id=package.name))}
  </td>
  <td>${views}</td>
  <td>${visits}</td>
  </tr>
  </py:for>
  </table>
 
 
  </div>
 
  <xi:include href="../../layout.html" />
  </html>
 
 
 
 
HAI Site <html xmlns:py="http://genshi.edgewall.org/"
  xmlns:i18n="http://genshi.edgewall.org/i18n"
  xmlns:xi="http://www.w3.org/2001/XInclude"
  py:strip="">
   
  <py:def function="page_title">Site analytics</py:def>
   
  <div py:match="content">
  <h1>Site statistics</h1>
   
  <form class="form-inline" action="${h.url_for(controller='ckanext.ga_report.controller:GaReport',action='index')}" method="get">
  <div class="controls">
  <select name="month">
  <py:for each="val,desc in c.months">
  <option value='${val}' py:attrs="{'selected': 'selected' if c.month == val else None}">${desc}</option>
  </py:for>
  </select>
  <input class="btn button" type='submit' value="Update"/>
  </div>
  </form>
   
  <p><a href="${h.url_for(controller='ckanext.ga_report.controller:GaReport',action='csv',month=c.month)}">Export data</a> as CSV</p>
   
  <div class="tabbable">
  <ul class="nav nav-tabs">
  <li class="active"><a href="#totals" data-toggle="tab">Totals</a></li>
  <li><a href="#browsers" data-toggle="tab">Browsers</a></li>
  <li><a href="#os" data-toggle="tab">Operating Systems</a></li>
  <li><a href="